From e32a45ed36d6000db4b39171149072d11b77af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Delafond?= Date: Sun, 13 Jul 2014 13:35:27 +0200 Subject: Imported Upstream version 8.0.7 --- contrib/lisp/org-e-odt.el | 3762 --------------------------------------------- 1 file changed, 3762 deletions(-) delete mode 100644 contrib/lisp/org-e-odt.el (limited to 'contrib/lisp/org-e-odt.el') diff --git a/contrib/lisp/org-e-odt.el b/contrib/lisp/org-e-odt.el deleted file mode 100644 index b2f7479..0000000 --- a/contrib/lisp/org-e-odt.el +++ /dev/null @@ -1,3762 +0,0 @@ -;;; org-e-odt.el --- OpenDocument Text exporter for Org-mode - -;; Copyright (C) 2010-2012 Free Software Foundation, Inc. - -;; Author: Jambunathan K -;; Keywords: outlines, hypermedia, calendar, wp -;; Homepage: http://orgmode.org - -;; This file is not part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;;; Code: - -(eval-when-compile - (require 'cl) - (require 'table)) -(require 'format-spec) -(require 'org-export) - -;;; Define Back-End - -(org-export-define-backend e-odt - ((bold . org-e-odt-bold) - (center-block . org-e-odt-center-block) - (clock . org-e-odt-clock) - (code . org-e-odt-code) - (drawer . org-e-odt-drawer) - (dynamic-block . org-e-odt-dynamic-block) - (entity . org-e-odt-entity) - (example-block . org-e-odt-example-block) - (export-block . org-e-odt-export-block) - (export-snippet . org-e-odt-export-snippet) - (fixed-width . org-e-odt-fixed-width) - (footnote-definition . org-e-odt-footnote-definition) - (footnote-reference . org-e-odt-footnote-reference) - (headline . org-e-odt-headline) - (horizontal-rule . org-e-odt-horizontal-rule) - (inline-src-block . org-e-odt-inline-src-block) - (inlinetask . org-e-odt-inlinetask) - (italic . org-e-odt-italic) - (item . org-e-odt-item) - (keyword . org-e-odt-keyword) - (latex-environment . org-e-odt-latex-environment) - (latex-fragment . org-e-odt-latex-fragment) - (line-break . org-e-odt-line-break) - (link . org-e-odt-link) - (macro . org-e-odt-macro) - (paragraph . org-e-odt-paragraph) - (plain-list . org-e-odt-plain-list) - (plain-text . org-e-odt-plain-text) - (planning . org-e-odt-planning) - (property-drawer . org-e-odt-property-drawer) - (quote-block . org-e-odt-quote-block) - (quote-section . org-e-odt-quote-section) - (radio-target . org-e-odt-radio-target) - (section . org-e-odt-section) - (special-block . org-e-odt-special-block) - (src-block . org-e-odt-src-block) - (statistics-cookie . org-e-odt-statistics-cookie) - (strike-through . org-e-odt-strike-through) - (subscript . org-e-odt-subscript) - (superscript . org-e-odt-superscript) - (table . org-e-odt-table) - (table-cell . org-e-odt-table-cell) - (table-row . org-e-odt-table-row) - (target . org-e-odt-target) - (template . org-e-odt-template) - (timestamp . org-e-odt-timestamp) - (underline . org-e-odt-underline) - (verbatim . org-e-odt-verbatim) - (verse-block . org-e-odt-verse-block)) - :export-block "ODT" - :options-alist - ((:odt-styles-file "ODT_STYLES_FILE" nil nil t) - (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))) - - -;;; Dependencies - -;;; Hooks - -;;; Function Declarations - -(declare-function org-id-find-id-file "org-id" (id)) -(declare-function hfy-face-to-style "htmlfontify" (fn)) -(declare-function hfy-face-or-def-to-name "htmlfontify" (fn)) -(declare-function archive-zip-extract "arc-mode.el" (archive name)) -(declare-function org-create-math-formula "org" (latex-frag &optional mathml-file)) -(declare-function browse-url-file-url "browse-url" (file)) - - - - -;;; Internal Variables - -(defconst org-e-odt-lib-dir - (file-name-directory load-file-name) - "Location of ODT exporter. -Use this to infer values of `org-e-odt-styles-dir' and -`org-e-odt-schema-dir'.") - -(defvar org-e-odt-data-dir - (expand-file-name "../../etc/" org-e-odt-lib-dir) - "Data directory for ODT exporter. -Use this to infer values of `org-e-odt-styles-dir' and -`org-e-odt-schema-dir'.") - -(defconst org-e-odt-special-string-regexps - '(("\\\\-" . "­\\1") ; shy - ("---\\([^-]\\)" . "—\\1") ; mdash - ("--\\([^-]\\)" . "–\\1") ; ndash - ("\\.\\.\\." . "…")) ; hellip - "Regular expressions for special string conversion.") - -(defconst org-e-odt-schema-dir-list - (list - (and org-e-odt-data-dir - (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out - (eval-when-compile - (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install - (expand-file-name "./schema/" org-e-odt-data-dir)))) - "List of directories to search for OpenDocument schema files. -Use this list to set the default value of -`org-e-odt-schema-dir'. The entries in this list are -populated heuristically based on the values of `org-e-odt-lib-dir' -and `org-e-odt-data-dir'.") - -(defconst org-e-odt-styles-dir-list - (list - (and org-e-odt-data-dir - (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out - (eval-when-compile - (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install - (expand-file-name "./styles/" org-e-odt-data-dir))) - (expand-file-name "../../etc/styles/" org-e-odt-lib-dir) ; git - (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa - (expand-file-name "./org/" data-directory) ; system - ) - "List of directories to search for OpenDocument styles files. -See `org-e-odt-styles-dir'. The entries in this list are populated -heuristically based on the values of `org-e-odt-lib-dir' and -`org-e-odt-data-dir'.") - -(defconst org-e-odt-styles-dir - (let* ((styles-dir - (catch 'styles-dir - (message "Debug (org-e-odt): Searching for OpenDocument styles files...") - (mapc (lambda (styles-dir) - (when styles-dir - (message "Debug (org-e-odt): Trying %s..." styles-dir) - (when (and (file-readable-p - (expand-file-name - "OrgOdtContentTemplate.xml" styles-dir)) - (file-readable-p - (expand-file-name - "OrgOdtStyles.xml" styles-dir))) - (message "Debug (org-e-odt): Using styles under %s" - styles-dir) - (throw 'styles-dir styles-dir)))) - org-e-odt-styles-dir-list) - nil))) - (unless styles-dir - (error "Error (org-e-odt): Cannot find factory styles files, aborting")) - styles-dir) - "Directory that holds auxiliary XML files used by the ODT exporter. - -This directory contains the following XML files - - \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These - XML files are used as the default values of - `org-e-odt-styles-file' and - `org-e-odt-content-template-file'. - -The default value of this variable varies depending on the -version of org in use and is initialized from -`org-e-odt-styles-dir-list'. Note that the user could be using org -from one of: org's own private git repository, GNU ELPA tar or -standard Emacs.") - -(defconst org-e-odt-bookmark-prefix "OrgXref.") - -(defconst org-e-odt-manifest-file-entry-tag - "\n") - -(defconst org-e-odt-file-extensions - '(("odt" . "OpenDocument Text") - ("ott" . "OpenDocument Text Template") - ("odm" . "OpenDocument Master Document") - ("ods" . "OpenDocument Spreadsheet") - ("ots" . "OpenDocument Spreadsheet Template") - ("odg" . "OpenDocument Drawing (Graphics)") - ("otg" . "OpenDocument Drawing Template") - ("odp" . "OpenDocument Presentation") - ("otp" . "OpenDocument Presentation Template") - ("odi" . "OpenDocument Image") - ("odf" . "OpenDocument Formula") - ("odc" . "OpenDocument Chart"))) - -(defvar org-e-odt-table-style-format - " - - - -" - "Template for auto-generated Table styles.") - -(defvar org-e-odt-automatic-styles '() - "Registry of automatic styles for various OBJECT-TYPEs. -The variable has the following form: -\(\(OBJECT-TYPE-A - \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\) - \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\) - \(OBJECT-TYPE-B - \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\) - \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\) - ...\). - -OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc. -OBJECT-PROPS is (typically) a plist created by passing -\"#+ATTR_ODT: \" option to `org-e-odt-parse-block-attributes'. - -Use `org-e-odt-add-automatic-style' to add update this variable.'") - -(defvar org-e-odt-object-counters nil - "Running counters for various OBJECT-TYPEs. -Use this to generate automatic names and style-names. See -`org-e-odt-add-automatic-style'.") - -(defvar org-e-odt-src-block-paragraph-format - " - - - - - " - "Custom paragraph style for colorized source and example blocks. -This style is much the same as that of \"OrgFixedWidthBlock\" -except that the foreground and background colors are set -according to the default face identified by the `htmlfontify'.") - -(defvar hfy-optimisations) -(defvar org-e-odt-embedded-formulas-count 0) -(defvar org-e-odt-entity-frame-styles - '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char")) - ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph")) - ("PageImage" "__Figure__" ("OrgPageImage" nil "page")) - ("CaptionedAs-CharImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgInlineImage" nil "as-char")) - ("CaptionedParagraphImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgImageCaptionFrame" nil "paragraph")) - ("CaptionedPageImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgPageImageCaptionFrame" nil "page")) - ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char")) - ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char")) - ("CaptionedDisplayFormula" "__MathFormula__" - ("OrgCaptionedFormula" nil "paragraph") - ("OrgFormulaCaptionFrame" nil "as-char")))) - -(defvar org-e-odt-embedded-images-count 0) -(defvar org-e-odt-image-size-probe-method - (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675 - '(emacs fixed)) - "Ordered list of methods for determining image sizes.") - -(defvar org-e-odt-default-image-sizes-alist - '(("as-char" . (5 . 0.4)) - ("paragraph" . (5 . 5))) - "Hardcoded image dimensions one for each of the anchor - 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 effective text area is 17.0 by 25.7 cm -(defvar org-e-odt-max-image-size '(17.0 . 20.0) - "Limiting dimensions for an embedded image.") - -(defvar org-e-odt-label-styles - '(("math-formula" "%c" "text" "(%n)") - ("math-label" "(%n)" "text" "(%n)") - ("category-and-value" "%e %n: %c" "category-and-value" "%e %n") - ("value" "%e %n: %c" "value" "%n")) - "Specify how labels are applied and referenced. -This is an alist where each element is of the -form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE -LABEL-REF-FMT). - -LABEL-ATTACH-FMT controls how labels and captions are attached to -an entity. It may contain following specifiers - %e, %n and %c. -%e is replaced with the CATEGORY-NAME. %n is replaced with -\" SEQNO \". %c is replaced -with CAPTION. See `org-e-odt-format-label-definition'. - -LABEL-REF-MODE and LABEL-REF-FMT controls how label references -are generated. The following XML is generated for a label -reference - \" LABEL-REF-FMT -\". LABEL-REF-FMT may contain following -specifiers - %e and %n. %e is replaced with the CATEGORY-NAME. -%n is replaced with SEQNO. See -`org-e-odt-format-label-reference'.") - -(defvar org-e-odt-category-map-alist - '(("__Table__" "Table" "value" "Table") - ("__Figure__" "Illustration" "value" "Figure") - ("__MathFormula__" "Text" "math-formula" "Equation") - ("__DvipngImage__" "Equation" "value" "Equation") - ("__Listing__" "Listing" "value" "Listing") - ;; ("__Table__" "Table" "category-and-value") - ;; ("__Figure__" "Figure" "category-and-value") - ;; ("__DvipngImage__" "Equation" "category-and-value") - ) - "Map a CATEGORY-HANDLE to OD-VARIABLE and LABEL-STYLE. -This is a list where each entry is of the form \\(CATEGORY-HANDLE -OD-VARIABLE LABEL-STYLE CATEGORY-NAME\\). CATEGORY_HANDLE -identifies the captionable entity in question. OD-VARIABLE is -the OpenDocument sequence counter associated with the entity. -These counters are declared within -\"...\" block of -`org-e-odt-content-template-file'. LABEL-STYLE is a key into -`org-e-odt-label-styles' and specifies how a given entity should -be captioned and referenced. CATEGORY-NAME is used for -qualifying captions on export. You can modify the CATEGORY-NAME -used in the exported document by modifying -`org-export-dictionary'. For example, an embedded image in an -English document is captioned as \"Figure 1: Orgmode Logo\", by -default. If you want the image to be captioned as \"Illustration -1: Orgmode Logo\" instead, install an entry in -`org-export-dictionary' which translates \"Figure\" to -\"Illustration\" when the language is \"en\" and encoding is -`:utf-8'.") - -(defvar org-e-odt-manifest-file-entries nil) -(defvar hfy-user-sheet-assoc) - -(defvar org-e-odt-zip-dir nil - "Temporary work directory for OpenDocument exporter.") - - - -;;; User Configuration Variables - -(defgroup org-export-e-odt nil - "Options for exporting Org mode files to ODT." - :tag "Org Export ODT" - :group 'org-export) - - -;;;; Debugging - -(defcustom org-e-odt-prettify-xml nil - "Specify whether or not the xml output should be prettified. -When this option is turned on, `indent-region' is run on all -component xml buffers before they are saved. Turn this off for -regular use. Turn this on if you need to examine the xml -visually." - :group 'org-export-e-odt - :version "24.1" - :type 'boolean) - - -;;;; Document schema - -(defcustom org-e-odt-schema-dir - (let* ((schema-dir - (catch 'schema-dir - (message "Debug (org-e-odt): Searching for OpenDocument schema files...") - (mapc - (lambda (schema-dir) - (when schema-dir - (message "Debug (org-e-odt): Trying %s..." schema-dir) - (when (and (file-readable-p - (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" - schema-dir)) - (file-readable-p - (expand-file-name "od-schema-v1.2-cs01.rnc" - schema-dir)) - (file-readable-p - (expand-file-name "schemas.xml" schema-dir))) - (message "Debug (org-e-odt): Using schema files under %s" - schema-dir) - (throw 'schema-dir schema-dir)))) - org-e-odt-schema-dir-list) - (message "Debug (org-e-odt): No OpenDocument schema files installed") - nil))) - schema-dir) - "Directory that contains OpenDocument schema files. - -This directory contains: -1. rnc files for OpenDocument schema -2. a \"schemas.xml\" file that specifies locating rules needed - for auto validation of OpenDocument XML files. - -Use the customize interface to set this variable. This ensures -that `rng-schema-locating-files' is updated and auto-validation -of OpenDocument XML takes place based on the value -`rng-nxml-auto-validate-flag'. - -The default value of this variable varies depending on the -version of org in use and is initialized from -`org-e-odt-schema-dir-list'. The OASIS schema files are available -only in the org's private git repository. It is *not* bundled -with GNU ELPA tar or standard Emacs distribution." - :type '(choice - (const :tag "Not set" nil) - (directory :tag "Schema directory")) - :group 'org-export-e-odt - :version "24.1" - :set - (lambda (var value) - "Set `org-e-odt-schema-dir'. -Also add it to `rng-schema-locating-files'." - (let ((schema-dir value)) - (set var - (if (and - (file-readable-p - (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir)) - (file-readable-p - (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir)) - (file-readable-p - (expand-file-name "schemas.xml" schema-dir))) - schema-dir - (when value - (message "Error (org-e-odt): %s has no OpenDocument schema files" - value)) - nil))) - (when org-e-odt-schema-dir - (eval-after-load 'rng-loc - '(add-to-list 'rng-schema-locating-files - (expand-file-name "schemas.xml" - org-e-odt-schema-dir)))))) - - -;;;; Document styles - -(defcustom org-e-odt-content-template-file nil - "Template file for \"content.xml\". -The exporter embeds the exported content just before -\"\" element. - -If unspecified, the file named \"OrgOdtContentTemplate.xml\" -under `org-e-odt-styles-dir' is used." - :type 'file - :group 'org-export-e-odt - :version "24.1") - -(defcustom org-e-odt-styles-file nil - "Default styles file for use with ODT export. -Valid values are one of: -1. nil -2. path to a styles.xml file -3. path to a *.odt or a *.ott file -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 -`org-e-odt-styles-dir' for more information. - -In case of option 3, the specified file is unzipped and the -styles.xml embedded therein is used. - -In case of option 4, the specified ODT-OR-OTT-FILE is unzipped -and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the -generated odt file. Use relative path for specifying the -FILE-MEMBERS. styles.xml must be specified as one of the -FILE-MEMBERS. - -Use options 1, 2 or 3 only if styles.xml alone suffices for -achieving the desired formatting. Use option 4, if the styles.xml -references additional files like header and footer images for -achieving the desired formatting. - -Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on -a per-file basis. For example, - -#+ODT_STYLES_FILE: \"/path/to/styles.xml\" or -#+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))." - :group 'org-export-e-odt - :version "24.1" - :type - '(choice - (const :tag "Factory settings" nil) - (file :must-match t :tag "styles.xml") - (file :must-match t :tag "ODT or OTT file") - (list :tag "ODT or OTT file + Members" - (file :must-match t :tag "ODF Text or Text Template file") - (cons :tag "Members" - (file :tag " Member" "styles.xml") - (repeat (file :tag "Member")))))) - -(defcustom org-e-odt-display-outline-level 2 - "Outline levels considered for enumerating captioned entities." - :group 'org-export-e-odt - :version "24.2" - :type 'integer) - -;;;; Document conversion - -(defcustom org-e-odt-convert-processes - '(("LibreOffice" - "soffice --headless --convert-to %f%x --outdir %d %i") - ("unoconv" - "unoconv -f %f -o %d %i")) - "Specify a list of document converters and their usage. -The converters in this list are offered as choices while -customizing `org-e-odt-convert-process'. - -This variable is a list where each element is of the -form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name -of the converter. CONVERTER-CMD is the shell command for the -converter and can contain format specifiers. These format -specifiers are interpreted as below: - -%i input file name in full -%I input file name as a URL -%f format of the output file -%o output file name in full -%O output file name as a URL -%d output dir in full -%D output dir as a URL. -%x extra options as set in `org-e-odt-convert-capabilities'." - :group 'org-export-e-odt - :version "24.1" - :type - '(choice - (const :tag "None" nil) - (alist :tag "Converters" - :key-type (string :tag "Converter Name") - :value-type (group (string :tag "Command line"))))) - -(defcustom org-e-odt-convert-process "LibreOffice" - "Use this converter to convert from \"odt\" format to other formats. -During customization, the list of converter names are populated -from `org-e-odt-convert-processes'." - :group 'org-export-e-odt - :version "24.1" - :type '(choice :convert-widget - (lambda (w) - (apply 'widget-convert (widget-type w) - (eval (car (widget-get w :args))))) - `((const :tag "None" nil) - ,@(mapcar (lambda (c) - `(const :tag ,(car c) ,(car c))) - org-e-odt-convert-processes)))) - -(defcustom org-e-odt-convert-capabilities - '(("Text" - ("odt" "ott" "doc" "rtf" "docx") - (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott") - ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html"))) - ("Web" - ("html") - (("pdf" "pdf") ("odt" "odt") ("html" "html"))) - ("Spreadsheet" - ("ods" "ots" "xls" "csv" "xlsx") - (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods") - ("xls" "xls") ("xlsx" "xlsx"))) - ("Presentation" - ("odp" "otp" "ppt" "pptx") - (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt") - ("pptx" "pptx") ("odg" "odg")))) - "Specify input and output formats of `org-e-odt-convert-process'. -More correctly, specify the set of input and output formats that -the user is actually interested in. - -This variable is an alist where each element is of the -form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST). -INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an -alist where each element is of the form (OUTPUT-FMT -OUTPUT-FILE-EXTENSION EXTRA-OPTIONS). - -The variable is interpreted as follows: -`org-e-odt-convert-process' can take any document that is in -INPUT-FMT-LIST and produce any document that is in the -OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have -OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT -serves dual purposes: -- It is used for populating completion candidates during - `org-e-odt-convert' commands. -- It is used as the value of \"%f\" specifier in - `org-e-odt-convert-process'. - -EXTRA-OPTIONS is used as the value of \"%x\" specifier in -`org-e-odt-convert-process'. - -DOCUMENT-CLASS is used to group a set of file formats in -INPUT-FMT-LIST in to a single class. - -Note that this variable inherently captures how LibreOffice based -converters work. LibreOffice maps documents of various formats -to classes like Text, Web, Spreadsheet, Presentation etc and -allow document of a given class (irrespective of it's source -format) to be converted to any of the export formats associated -with that class. - -See default setting of this variable for an typical -configuration." - :group 'org-export-e-odt - :version "24.1" - :type - '(choice - (const :tag "None" nil) - (alist :tag "Capabilities" - :key-type (string :tag "Document Class") - :value-type - (group (repeat :tag "Input formats" (string :tag "Input format")) - (alist :tag "Output formats" - :key-type (string :tag "Output format") - :value-type - (group (string :tag "Output file extension") - (choice - (const :tag "None" nil) - (string :tag "Extra options")))))))) - -(defcustom org-e-odt-preferred-output-format nil - "Automatically post-process to this format after exporting to \"odt\". -Interactive commands `org-export-as-e-odt' and -`org-export-as-e-odt-and-open' export first to \"odt\" format and -then use `org-e-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-e-odt-convert-capabilities'." - :group 'org-export-e-odt - :version "24.1" - :type '(choice :convert-widget - (lambda (w) - (apply 'widget-convert (widget-type w) - (eval (car (widget-get w :args))))) - `((const :tag "None" nil) - ,@(mapcar (lambda (c) - `(const :tag ,c ,c)) - (org-e-odt-reachable-formats "odt"))))) - - -;;;; Drawers - -(defcustom org-e-odt-format-drawer-function nil - "Function called to format a drawer in HTML code. - -The function must accept two parameters: - NAME the drawer name, like \"LOGBOOK\" - CONTENTS the contents of the drawer. - -The function should return the string to be exported. - -For example, the variable could be set to the following function -in order to mimic default behaviour: - -\(defun org-e-odt-format-drawer-default \(name contents\) - \"Format a drawer element for HTML export.\" - contents\)" - :group 'org-export-e-odt - :type 'function) - - -;;;; Headline - -(defcustom org-e-odt-format-headline-function nil - "Function to format headline text. - -This function will be called with 5 arguments: -TODO the todo keyword \(string or nil\). -TODO-TYPE the type of todo \(symbol: `todo', `done', nil\) -PRIORITY the priority of the headline \(integer or nil\) -TEXT the main headline text \(string\). -TAGS the tags string, separated with colons \(string or nil\). - -The function result will be used in the section format string. - -As an example, one could set the variable to the following, in -order to reproduce the default set-up: - -\(defun org-e-odt-format-headline \(todo todo-type priority text tags\) - \"Default format function for an headline.\" - \(concat \(when todo - \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\) - \(when priority - \(format \"\\\\framebox{\\\\#%c} \" priority\)\) - text - \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)" - :group 'org-export-e-odt - :type 'function) - - -;;;; Inlinetasks - -(defcustom org-e-odt-format-inlinetask-function nil - "Function called to format an inlinetask in HTML code. - -The function must accept six parameters: - TODO the todo keyword, as a string - TODO-TYPE the todo type, a symbol among `todo', `done' and nil. - PRIORITY the inlinetask priority, as a string - NAME the inlinetask name, as a string. - TAGS the inlinetask tags, as a string. - CONTENTS the contents of the inlinetask, as a string. - -The function should return the string to be exported. - -For example, the variable could be set to the following function -in order to mimic default behaviour: - -\(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\) -\"Format an inline task element for HTML export.\" - \(let \(\(full-title - \(concat - \(when todo - \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\) - \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\) - title - \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\) - \(format \(concat \"\\\\begin{center}\\n\" - \"\\\\fbox{\\n\" - \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\" - \"%s\\n\\n\" - \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\" - \"%s\" - \"\\\\end{minipage}}\" - \"\\\\end{center}\"\) - full-title contents\)\)" - :group 'org-export-e-odt - :type 'function) - - -;;;; Links - -(defcustom org-e-odt-inline-image-rules - '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\)\\'")) - "Rules characterizing image files that can be inlined into HTML. - -A rule consists in an association whose key is the type of link -to consider, and value is a regexp that will be matched against -link's path. - -Note that, by default, the image extension *actually* allowed -depend on the way the HTML file is processed. When used with -pdflatex, pdf, jpg and png images are OK. When processing -through dvi to Postscript, only ps and eps are allowed. The -default we use here encompasses both." - :group 'org-export-e-odt - :type '(alist :key-type (string :tag "Type") - :value-type (regexp :tag "Path"))) - -(defcustom org-e-odt-pixels-per-inch display-pixels-per-inch - "Scaling factor for converting images pixels to inches. -Use this for sizing of embedded images. See Info node `(org) -Images in ODT export' for more information." - :type 'float - :group 'org-export-e-odt - :version "24.1") - - -;;;; Plain text - -(defcustom org-e-odt-quotes - '(("fr" - ("\\(\\s-\\|[[(]\\|^\\)\"" . "« ") - ("\\(\\S-\\)\"" . "» ") - ("\\(\\s-\\|(\\|^\\)'" . "'")) - ("en" - ("\\(\\s-\\|[[(]\\|^\\)\"" . "“") - ("\\(\\S-\\)\"" . "”") - ("\\(\\s-\\|(\\|^\\)'" . "‘") - ("\\(\\S-\\)'" . "’"))) - "Alist for quotes to use when converting english double-quotes. - -The CAR of each item in this alist is the language code. -The CDR of each item in this alist is a list of three CONS: -- the first CONS defines the opening quote; -- the second CONS defines the closing quote; -- the last CONS defines single quotes. - -For each item in a CONS, the first string is a regexp -for allowed characters before/after the quote, the second -string defines the replacement string for this quote." - :group 'org-export-e-odt - :type '(list - (cons :tag "Opening quote" - (string :tag "Regexp for char before") - (string :tag "Replacement quote ")) - (cons :tag "Closing quote" - (string :tag "Regexp for char after ") - (string :tag "Replacement quote ")) - (cons :tag "Single quote" - (string :tag "Regexp for char before") - (string :tag "Replacement quote ")))) - - -;;;; Src Block - -(defcustom org-e-odt-create-custom-styles-for-srcblocks t - "Whether custom styles for colorized source blocks be automatically created. -When this option is turned on, the exporter creates custom styles -for source blocks based on the advice of `htmlfontify'. Creation -of custom styles happen as part of `org-e-odt-hfy-face-to-css'. - -When this option is turned off exporter does not create such -styles. - -Use the latter option if you do not want the custom styles to be -based on your current display settings. It is necessary that the -styles.xml already contains needed styles for colorizing to work. - -This variable is effective only if -`org-e-odt-fontify-srcblocks' is turned on." - :group 'org-export-e-odt - :version "24.1" - :type 'boolean) - -(defcustom org-e-odt-fontify-srcblocks t - "Specify whether or not source blocks need to be fontified. -Turn this option on if you want to colorize the source code -blocks in the exported file. For colorization to work, you need -to make available an enhanced version of `htmlfontify' library." - :type 'boolean - :group 'org-export-e-odt - :version "24.1") - - -;;;; Table - -(defcustom org-e-odt-table-caption-above t - "When non-nil, place caption string at the beginning of the table. -Otherwise, place it near the end." - :group 'org-export-e-odt - :type 'boolean) - -(defcustom org-e-odt-table-styles - '(("OrgEquation" "OrgEquation" - ((use-first-column-styles . t) - (use-last-column-styles . t)))) - "Specify how Table Styles should be derived from a Table Template. -This is a list where each element is of the -form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS). - -TABLE-STYLE-NAME is the style associated with the table through -\"#+ATTR_ODT: :style TABLE-STYLE-NAME\" line. - -TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic -TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined -below) that is included in -`org-e-odt-content-template-file'. - -TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE + - \"TableCell\" -PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE + - \"TableParagraph\" -TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" | - \"FirstRow\" | \"LastRow\" | - \"EvenRow\" | \"OddRow\" | - \"EvenColumn\" | \"OddColumn\" | \"\" -where \"+\" above denotes string concatenation. - -TABLE-CELL-OPTIONS is an alist where each element is of the -form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF). -TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' | - `use-last-row-styles' | - `use-first-column-styles' | - `use-last-column-styles' | - `use-banding-rows-styles' | - `use-banding-columns-styles' | - `use-first-row-styles' -ON-OR-OFF := `t' | `nil' - -For example, with the following configuration - -\(setq org-e-odt-table-styles - '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\" - \(\(use-first-row-styles . t\) - \(use-first-column-styles . t\)\)\) - \(\"TableWithHeaderColumns\" \"Custom\" - \(\(use-first-column-styles . t\)\)\)\)\) - -1. A table associated with \"TableWithHeaderRowsAndColumns\" - style will use the following table-cell styles - - \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\", - \"CustomTableCell\" and the following paragraph styles - \"CustomFirstRowTableParagraph\", - \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\" - as appropriate. - -2. A table associated with \"TableWithHeaderColumns\" style will - use the following table-cell styles - - \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the - following paragraph styles - \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\" - as appropriate.. - -Note that TABLE-TEMPLATE-NAME corresponds to the -\"\" elements contained within -\"\". The entries (TABLE-STYLE-NAME -TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to -\"table:template-name\" and \"table:use-first-row-styles\" etc -attributes of \"\" element. Refer ODF-1.2 -specification for more information. Also consult the -implementation filed under `org-e-odt-get-table-cell-styles'. - -The TABLE-STYLE-NAME \"OrgEquation\" is used internally for -formatting of numbered display equations. Do not delete this -style from the list." - :group 'org-export-e-odt - :version "24.1" - :type '(choice - (const :tag "None" nil) - (repeat :tag "Table Styles" - (list :tag "Table Style Specification" - (string :tag "Table Style Name") - (string :tag "Table Template Name") - (alist :options (use-first-row-styles - use-last-row-styles - use-first-column-styles - use-last-column-styles - use-banding-rows-styles - use-banding-columns-styles) - :key-type symbol - :value-type (const :tag "True" t)))))) - - - -;;; Internal functions - -;;;; Date - -(defun org-e-odt--date (&optional org-ts fmt) - (save-match-data - (let* ((time - (and (stringp org-ts) - (string-match org-ts-regexp0 org-ts) - (apply 'encode-time - (org-fix-decoded-time - (org-parse-time-string (match-string 0 org-ts) t))))) - date) - (cond - (fmt (format-time-string fmt time)) - (t (setq date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time)) - (format "%s:%s" (substring date 0 -2) (substring date -2))))))) - -;;;; Frame - -(defun org-e-odt--frame (text width height style &optional extra - anchor-type) - (let ((frame-attrs - (concat - (if width (format " svg:width=\"%0.2fcm\"" width) "") - (if height (format " svg:height=\"%0.2fcm\"" height) "") - extra - (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph"))))) - (format - "\n\n%s\n" - style frame-attrs - (concat text - (let ((title (get-text-property 0 :title text)) - (desc (get-text-property 0 :description text))) - (concat (and title - (format "%s" - (org-e-odt-encode-plain-text title t))) - (and desc - (format "%s" - (org-e-odt-encode-plain-text desc t))))))))) - -;;;; Library wrappers - -(defun org-e-odt--adopt-elements (parent &rest children) - (prog1 parent - (mapc (lambda (child) - (let ((parent-1 (org-element-adopt-element parent child nil))) - (assert (eq parent-1 parent)))) - children))) - -(defun org-e-odt--zip-extract (archive members target) - (when (atom members) (setq members (list members))) - (mapc (lambda (archive member target) - (require 'arc-mode) - (let* ((--quote-file-name - ;; This is shamelessly stolen from `archive-zip-extract'. - (lambda (name) - (if (or (not (memq system-type '(windows-nt ms-dos))) - (and (boundp 'w32-quote-process-args) - (null w32-quote-process-args))) - (shell-quote-argument name) - name))) - (target (funcall --quote-file-name target)) - (archive (expand-file-name archive)) - (archive-zip-extract - (list "unzip" "-qq" "-o" "-d" target)) - exit-code command-output) - (setq command-output - (with-temp-buffer - (setq exit-code (archive-zip-extract archive member)) - (buffer-string))) - (unless (zerop exit-code) - (message command-output) - (error "Extraction failed")))) - members)) - -;;;; Textbox - -(defun org-e-odt--textbox (text width height style &optional - extra anchor-type) - (org-e-odt--frame - (format "\n%s\n" - (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2)) - (and (not width) - (format " fo:min-width=\"%0.2fcm\"" (or width .2)))) - text) - width nil style extra anchor-type)) - - - -;;;; Table of Contents - -(defun org-e-odt-begin-toc (index-title depth) - (concat - (format " - - - %s -" depth index-title) - - (let ((levels (number-sequence 1 10))) - (mapconcat - (lambda (level) - (format - " - - - - - - -" level level)) levels "")) - - (format " - - - - - %s - - " index-title))) - -(defun org-e-odt-end-toc () - (format " - - -")) - - - -(defun* org-e-odt-format-toc-headline - (todo todo-type priority text tags - &key level section-number headline-label &allow-other-keys) - (setq text (concat - (and org-export-with-section-numbers - (concat section-number ". ")) - text - (and tags - (concat - "" - (format "%s" - "OrgTag" tags))))) - (when todo - (setq text (format "%s" - "OrgTodo" text))) - (org-e-odt-format-link text (concat "#" headline-label) t)) - -(defun org-e-odt-toc (depth info) - (assert (wholenump depth)) - (let* ((title (org-export-translate "Table of Contents" :utf-8 info)) - (headlines (org-export-collect-headlines info depth))) - - (when headlines - (concat - (org-e-odt-begin-toc title depth) - - (mapconcat - (lambda (headline) - (let* ((entry (org-e-odt-format-headline--wrap - headline info 'org-e-odt-format-toc-headline)) - (level (org-export-get-relative-level headline info)) - (style (format "Contents_20_%d" level))) - (format "\n%s" - style entry))) - headlines "\n") - - (org-e-odt-end-toc))))) - - -;;;; Document styles - -(defun org-e-odt-add-automatic-style (object-type &optional object-props) - "Create an automatic style of type OBJECT-TYPE with param OBJECT-PROPS. -OBJECT-PROPS is (typically) a plist created by passing -\"#+ATTR_ODT: \" option of the object in question to -`org-e-odt-parse-block-attributes'. - -Use `org-e-odt-object-counters' to generate an automatic -OBJECT-NAME and STYLE-NAME. If OBJECT-PROPS is non-nil, add a -new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME -. STYLE-NAME)." - (assert (stringp object-type)) - (let* ((object (intern object-type)) - (seqvar object) - (seqno (1+ (or (plist-get org-e-odt-object-counters seqvar) 0))) - (object-name (format "%s%d" object-type seqno)) style-name) - (setq org-e-odt-object-counters - (plist-put org-e-odt-object-counters seqvar seqno)) - (when object-props - (setq style-name (format "Org%s" object-name)) - (setq org-e-odt-automatic-styles - (plist-put org-e-odt-automatic-styles object - (append (list (list style-name object-props)) - (plist-get org-e-odt-automatic-styles object))))) - (cons object-name style-name))) - - -;;;; Caption and Labels - - -(defun org-e-odt--wrap-label (element output) - "Wrap label associated to ELEMENT around OUTPUT, if appropriate. -This function shouldn't be used for floats. See -`org-e-odt--caption/label-string'." - ;; (let ((label (org-element-property :name element))) - ;; (if (or (not output) (not label) (string= output "") (string= label "")) - ;; output - ;; (concat (format "\\label{%s}\n" label) output))) - output) - - -(defun org-e-odt--caption/label-string (caption label info) - "Return caption and label HTML string for floats. - -CAPTION is a cons cell of secondary strings, the car being the -standard caption and the cdr its short form. LABEL is a string -representing the label. INFO is a plist holding contextual -information. - -If there's no caption nor label, return the empty string. - -For non-floats, see `org-e-odt--wrap-label'." - (setq label nil) ;; FIXME - - (let ((label-str (if label (format "\\label{%s}" label) ""))) - (cond - ((and (not caption) (not label)) "") - ((not caption) (format "\\label{%s}\n" label)) - ;; Option caption format with short name. - ((cdr caption) - (format "\\caption[%s]{%s%s}\n" - (org-export-data (cdr caption) info) - label-str - (org-export-data (car caption) info))) - ;; Standard caption format. - ;; (t (format "\\caption{%s%s}\n" - ;; label-str - ;; (org-export-data (car caption) info))) - (t (org-export-data (car caption) info))))) - -;;;; Checkbox - -(defun org-e-odt--checkbox (item) - "Return check-box string associated to ITEM." - (let ((checkbox (org-element-property :checkbox item))) - (if (not checkbox) "" - (format "%s" - "OrgCode" (case checkbox - (on "[✓] ") ; CHECK MARK - (off "[ ] ") - (trans "[-] ")))))) - - - -;;; Template - -(defun org-e-odt-template (contents info) - "Return complete document string after HTML conversion. -CONTENTS is the transcoded contents string. RAW-DATA is the -original parsed data. INFO is a plist holding export options." - ;; Write meta file. - (let ((title (org-export-data (plist-get info :title) info)) - (author (let ((author (plist-get info :author))) - (if (not author) "" (org-export-data author info)))) - (date (org-e-odt--date - (org-export-data (plist-get info :date) info))) - (email (plist-get info :email)) - (keywords (plist-get info :keywords)) - (description (plist-get info :description))) - (write-region - (concat - " - - \n" - (format "%s\n" author) - (format "%s\n" author) - (format "%s\n" date) - (format "%s\n" date) - (format "%s\n" - (let ((creator-info (plist-get info :with-creator))) - (if (or (not creator-info) (eq creator-info 'comment)) "" - (plist-get info :creator)))) - (format "%s\n" keywords) - (format "%s\n" description) - (format "%s\n" title) - "\n" - " \n" "") - nil (concat org-e-odt-zip-dir "meta.xml")) - ;; Add meta.xml in to manifest. - (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml")) - - ;; Update styles file. - ;; Copy styles.xml. Also dump htmlfontify styles, if there is any. - ;; Write styles file. - (let* ((styles-file (plist-get info :odt-styles-file)) - (styles-file (and styles-file (read (org-trim styles-file)))) - ;; Non-availability of styles.xml is not a critical - ;; error. For now throw an error purely for aesthetic - ;; reasons. - (styles-file (or styles-file - org-e-odt-styles-file - (expand-file-name "OrgOdtStyles.xml" - org-e-odt-styles-dir) - (error "org-e-odt: Missing styles file?")))) - (cond - ((listp styles-file) - (let ((archive (nth 0 styles-file)) - (members (nth 1 styles-file))) - (org-e-odt--zip-extract archive members org-e-odt-zip-dir) - (mapc - (lambda (member) - (when (org-file-image-p member) - (let* ((image-type (file-name-extension member)) - (media-type (format "image/%s" image-type))) - (org-e-odt-create-manifest-file-entry media-type member)))) - members))) - ((and (stringp styles-file) (file-exists-p styles-file)) - (let ((styles-file-type (file-name-extension styles-file))) - (cond - ((string= styles-file-type "xml") - (copy-file styles-file (concat org-e-odt-zip-dir "styles.xml") t)) - ((member styles-file-type '("odt" "ott")) - (org-e-odt--zip-extract styles-file "styles.xml" org-e-odt-zip-dir))))) - (t - (error (format "Invalid specification of styles.xml file: %S" - org-e-odt-styles-file)))) - - ;; create a manifest entry for styles.xml - (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml") - - ;; FIXME: Who is opening an empty styles.xml before this point? - (with-current-buffer - (find-file-noselect (concat org-e-odt-zip-dir "styles.xml") t) - (revert-buffer t t) - - ;; Write custom styles for source blocks - ;; Save STYLES used for colorizing of source blocks. - ;; Update styles.xml with styles that were collected as part of - ;; `org-e-odt-hfy-face-to-css' callbacks. - (let ((styles (mapconcat (lambda (style) (format " %s\n" (cddr style))) - hfy-user-sheet-assoc ""))) - (when styles - (goto-char (point-min)) - (when (re-search-forward "" nil t) - (goto-char (match-beginning 0)) - (insert "\n\n" styles "\n")))) - - ;; Update styles.xml - take care of outline numbering - - ;; 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 - ;; 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 - ;; 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. - (set (make-local-variable 'backup-inhibited) t) - - ;; Outline numbering is retained only upto LEVEL. - ;; To disable outline numbering pass a LEVEL of 0. - - (goto-char (point-min)) - (let ((regex - "]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>") - (replacement - "")) - (while (re-search-forward regex nil t) - (unless (let ((sec-num (plist-get info :section-numbers)) - (level (string-to-number (match-string 2)))) - (if (wholenump sec-num) (<= level sec-num) sec-num)) - (replace-match replacement t nil)))) - (save-buffer 0))) - ;; Update content.xml. - (with-temp-buffer - (insert-file-contents - (or org-e-odt-content-template-file - (expand-file-name "OrgOdtContentTemplate.xml" - org-e-odt-styles-dir))) - ;; Write automatic styles. - ;; - Position the cursor. - (goto-char (point-min)) - (re-search-forward " " nil t) - (goto-char (match-beginning 0)) - ;; - Dump automatic table styles - (loop for (style-name props) in - (plist-get org-e-odt-automatic-styles 'Table) do - (when (setq props (or (plist-get props :rel-width) 96)) - (insert (format org-e-odt-table-style-format style-name props)))) - ;; Update display level. - ;; - Remove existing sequence decls. Also position the cursor. - (goto-char (point-min)) - (when (re-search-forward "" nil nil))) - ;; Update sequence decls according to user preference. - (insert - (format - "\n\n%s\n" - (mapconcat - (lambda (x) - (format - "" - org-e-odt-display-outline-level (nth 1 x))) - org-e-odt-category-map-alist "\n"))) - ;; Position the cursor to document body. - (goto-char (point-min)) - (re-search-forward "" nil nil) - (goto-char (match-beginning 0)) - - ;; Preamble - Title, Author, Date etc. - (insert - (let* ((title (org-export-data (plist-get info :title) info)) - (author (and (plist-get info :with-author) - (let ((auth (plist-get info :author))) - (and auth (org-export-data auth info))))) - (date (org-export-data (plist-get info :date) info)) - (iso-date (org-e-odt--date date)) - (date (org-e-odt--date date "%d %b %Y")) - (email (plist-get info :email)) - ;; switch on or off above vars based on user settings - (author (and (plist-get info :with-author) (or author email))) - ;; (date (and (plist-get info :time-stamp-file) date)) - (email (and (plist-get info :with-email) email))) - (concat - ;; title - (when title - (concat - (format "\n%s" - "OrgTitle" (format "\n%s" title)) - ;; separator - "\n")) - (cond - ((and author (not email)) - ;; author only - (concat - (format "\n%s" - "OrgSubtitle" - (format "%s" author)) - ;; separator - "\n")) - ((and author email) - ;; author and email - (concat - (format "\n%s" - "OrgSubtitle" - (org-e-odt-format-link - (format "%s" author) - (concat "mailto:" email))) - ;; separator - "\n"))) - ;; date - (when date - (concat - (format - "\n%s" - "OrgSubtitle" - (format - "\n%s" - - "N75" iso-date date)) - ;; separator - ""))))) - - ;; Table of Contents - (let ((depth (plist-get info :with-toc))) - (when (wholenump depth) (insert (org-e-odt-toc depth info)))) - ;; Contents. - (insert contents) - ;; Return contents. - (buffer-substring-no-properties (point-min) (point-max)))) - - - -;;; Transcode Functions - -;;;; Bold - -(defun org-e-odt-bold (bold contents info) - "Transcode BOLD from Org to ODT. -CONTENTS is the text with bold markup. INFO is a plist holding -contextual information." - (format "%s" - "Bold" contents)) - - -;;;; Center Block - -(defun org-e-odt-center-block (center-block contents info) - "Transcode a CENTER-BLOCK element from Org to ODT. -CONTENTS holds the contents of the center block. INFO is a plist -holding contextual information." - (org-e-odt--wrap-label center-block contents)) - - -;;;; Clock - -(defun org-e-odt-clock (clock contents info) - "Transcode a CLOCK element from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (format "%s" - "OrgTimestampWrapper" - (concat - (format "%s" - "OrgTimestampKeyword" org-clock-string) - (format "%s" - "OrgTimestamp" - (concat (org-translate-time - (org-element-property :value clock)) - (let ((time (org-element-property :time clock))) - (and time (format " (%s)" time)))))))) - - -;;;; Code - -(defun org-e-odt-code (code contents info) - "Transcode a CODE object from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (format "%s" - "OrgCode" (org-element-property :value code))) - - -;;;; Comment - -;; Comments are ignored. - - -;;;; Comment Block - -;; Comment Blocks are ignored. - - -;;;; Drawer - -(defun org-e-odt-drawer (drawer contents info) - "Transcode a DRAWER element from Org to ODT. -CONTENTS holds the contents of the block. INFO is a plist -holding contextual information." - (let* ((name (org-element-property :drawer-name drawer)) - (output (if (functionp org-e-odt-format-drawer-function) - (funcall org-e-odt-format-drawer-function - name contents) - ;; If there's no user defined function: simply - ;; display contents of the drawer. - contents))) - (org-e-odt--wrap-label drawer output))) - - -;;;; Dynamic Block - -(defun org-e-odt-dynamic-block (dynamic-block contents info) - "Transcode a DYNAMIC-BLOCK element from Org to ODT. -CONTENTS holds the contents of the block. INFO is a plist -holding contextual information. See `org-export-data'." - (org-e-odt--wrap-label dynamic-block contents)) - - -;;;; Entity - -(defun org-e-odt-entity (entity contents info) - "Transcode an ENTITY object from Org to ODT. -CONTENTS are the definition itself. INFO is a plist holding -contextual information." - ;; (let ((ent (org-element-property :latex entity))) - ;; (if (org-element-property :latex-math-p entity) - ;; (format "$%s$" ent) - ;; ent)) - (org-element-property :utf-8 entity)) - - -;;;; Example Block - -(defun org-e-odt-example-block (example-block contents info) - "Transcode a EXAMPLE-BLOCK element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (org-e-odt--wrap-label - example-block (org-e-odt-format-code example-block info))) - - -;;;; Export Snippet - -(defun org-e-odt-export-snippet (export-snippet contents info) - "Transcode a EXPORT-SNIPPET object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (when (eq (org-export-snippet-backend export-snippet) 'e-odt) - (org-element-property :value export-snippet))) - - -;;;; Export Block - -(defun org-e-odt-export-block (export-block contents info) - "Transcode a EXPORT-BLOCK element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (when (string= (org-element-property :type export-block) "ODT") - (org-remove-indentation (org-element-property :value export-block)))) - - -;;;; Fixed Width - -(defun org-e-odt-fixed-width (fixed-width contents info) - "Transcode a FIXED-WIDTH element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (org-e-odt--wrap-label - fixed-width (org-e-odt-do-format-code - (org-element-property :value fixed-width)))) - - -;;;; Footnote Definition - -;; Footnote Definitions are ignored. - - -;;;; Footnote Reference - -(defun org-e-odt-footnote-reference (footnote-reference contents info) - "Transcode a FOOTNOTE-REFERENCE element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (let ((--format-footnote-definition - (function - (lambda (n def) - (setq n (format "%d" n)) - (let ((id (concat "fn" n)) - (note-class "footnote") - (par-style "Footnote")) - (format - "%s" - id note-class - (concat - (format "%s" n) - (format "%s" def))))))) - (--format-footnote-reference - (function - (lambda (n) - (setq n (format "%d" n)) - (let ((note-class "footnote") - (ref-format "text") - (ref-name (concat "fn" n))) - (format - "%s" - "OrgSuperscript" - (format "%s" - note-class ref-format ref-name n))))))) - (concat - ;; Insert separator between two footnotes in a row. - (let ((prev (org-export-get-previous-element footnote-reference info))) - (and (eq (org-element-type prev) 'footnote-reference) - (format "%s" - "OrgSuperscript" ","))) - ;; Trancode footnote reference. - (let ((n (org-export-get-footnote-number footnote-reference info))) - (cond - ((not (org-export-footnote-first-reference-p footnote-reference info)) - (funcall --format-footnote-reference n)) - ;; Inline definitions are secondary strings. - ;; Non-inline footnotes definitions are full Org data. - (t - (let* ((raw (org-export-get-footnote-definition footnote-reference - info)) - (def (let ((def (org-trim (org-export-data raw info)))) - (if (eq (org-element-type raw) 'org-data) def - (format "\n%s" - "Footnote" def))))) - (funcall --format-footnote-definition n def)))))))) - - -;;;; Headline - -(defun* org-e-odt-format-headline - (todo todo-type priority text tags - &key level section-number headline-label &allow-other-keys) - (concat - ;; Todo. - (and todo - (concat - (let ((style (if (member todo org-done-keywords) "OrgDone" "OrgTodo"))) - (format "%s" - style todo)) " ")) - ;; Title. - text - ;; Tags. - (and tags - (concat "" - (format "%s" - "OrgTag" (mapconcat 'org-trim tags " : ")))))) - -(defun org-e-odt-format-headline--wrap (headline info - &optional format-function - &rest extra-keys) - "Transcode an HEADLINE element from Org to ODT. -CONTENTS holds the contents of the headline. INFO is a plist -holding contextual information." - (let* ((level (+ (org-export-get-relative-level headline info))) - (headline-number (org-export-get-headline-number headline info)) - (section-number (and (org-export-numbered-headline-p headline info) - (mapconcat 'number-to-string - headline-number "."))) - (todo (and (plist-get info :with-todo-keywords) - (let ((todo (org-element-property :todo-keyword headline))) - (and todo (org-export-data todo info))))) - (todo-type (and todo (org-element-property :todo-type headline))) - (priority (and (plist-get info :with-priority) - (org-element-property :priority headline))) - (text (org-export-data (org-element-property :title headline) info)) - (tags (and (plist-get info :with-tags) - (org-export-get-tags headline info))) - (headline-label (concat "sec-" (mapconcat 'number-to-string - headline-number "-"))) - (format-function (cond - ((functionp format-function) format-function) - ((functionp org-e-odt-format-headline-function) - (function* - (lambda (todo todo-type priority text tags - &allow-other-keys) - (funcall org-e-odt-format-headline-function - todo todo-type priority text tags)))) - (t 'org-e-odt-format-headline)))) - (apply format-function - todo todo-type priority text tags - :headline-label headline-label :level level - :section-number section-number extra-keys))) - - -(defun org-e-odt-begin-plain-list (ltype &optional continue-numbering) - (unless (member ltype '(ordered unordered descriptive)) - (error "Unknown list type: %s" ltype)) - (let ((style-name (assoc-default ltype - '((ordered . "OrgNumberedList") - (unordered . "OrgBulletedList") - (descriptive . "OrgDescriptionList"))))) - (format "" - style-name (if continue-numbering "true" "false")))) - -(defun org-e-odt-headline (headline contents info) - "Transcode an HEADLINE element from Org to ODT. -CONTENTS holds the contents of the headline. INFO is a plist -holding contextual information." - (let* ((numberedp (org-export-numbered-headline-p headline info)) - ;; Get level relative to current parsed data. - (level (org-export-get-relative-level headline info)) - (text (org-export-data (org-element-property :title headline) info)) - ;; Create the headline text. - (full-text (org-e-odt-format-headline--wrap headline info))) - (cond - ;; Case 1: This is a footnote section: ignore it. - ((org-element-property :footnote-section-p headline) nil) - ;; Case 2. This is a deep sub-tree: export it as a list item. - ;; Also export as items headlines for which no section - ;; format has been found. - ;; FIXME - ;; ((org-export-low-level-p headline info) - ;; ;; Build the real contents of the sub-tree. - ;; (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME - ;; (itemized-body (org-e-odt-format-list-item - ;; contents type nil nil full-text))) - ;; (concat - ;; (and (org-export-first-sibling-p headline info) - ;; (org-e-odt-begin-plain-list type)) - ;; itemized-body - ;; (and (org-export-last-sibling-p headline info) - ;; "")))) - ;; Case 3. Standard headline. Export it as a section. - (t - (let* ((extra-ids (list (org-element-property :custom-id headline) - (org-element-property :id headline))) - (extra-ids nil) ; FIXME - (id (concat "sec-" (mapconcat 'number-to-string - (org-export-get-headline-number - headline info) "-")))) - (concat - (format - "\n%s%s" - (format "Heading_20_%s" level) - level - ;; Extra targets. - (mapconcat (lambda (x) - (when x - (let ((x (if (org-uuidgen-p x) (concat "ID-" x) x))) - (org-e-odt-format-target - "" (org-export-solidify-link-text x))))) - extra-ids "") - ;; Title. - (org-e-odt-format-target full-text id)) - contents)))))) - - -;;;; Horizontal Rule - -(defun org-e-odt-horizontal-rule (horizontal-rule contents info) - "Transcode an HORIZONTAL-RULE object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (org-e-odt--wrap-label - horizontal-rule - (format "\n%s" - "Horizontal_20_Line" ""))) - - -;;;; Inline Babel Call - -;; Inline Babel Calls are ignored. - - -;;;; Inline Src Block - -(defun org-e-odt--find-verb-separator (s) - "Return a character not used in string S. -This is used to choose a separator for constructs like \\verb." - (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}")) - (loop for c across ll - when (not (string-match (regexp-quote (char-to-string c)) s)) - return (char-to-string c)))) - -(defun org-e-odt-inline-src-block (inline-src-block contents info) - "Transcode an INLINE-SRC-BLOCK element from Org to ODT. -CONTENTS holds the contents of the item. INFO is a plist holding -contextual information." - (let* ((org-lang (org-element-property :language inline-src-block)) - (code (org-element-property :value inline-src-block)) - (separator (org-e-odt--find-verb-separator code))) - (error "FIXME"))) - - -;;;; Inlinetask - -(defun org-e-odt-inlinetask (inlinetask contents info) - "Transcode an INLINETASK element from Org to ODT. -CONTENTS holds the contents of the block. INFO is a plist -holding contextual information." - (cond - ;; If `org-e-odt-format-inlinetask-function' is provided, call it - ;; with appropriate arguments. - ((functionp org-e-odt-format-inlinetask-function) - (let ((format-function - (function* - (lambda (todo todo-type priority text tags - &key contents &allow-other-keys) - (funcall org-e-odt-format-inlinetask-function - todo todo-type priority text tags contents))))) - (org-e-odt-format-headline--wrap - inlinetask info format-function :contents contents))) - ;; Otherwise, use a default template. - (t (org-e-odt--wrap-label - inlinetask - (format "\n%s" - "Text_20_body" - (org-e-odt--textbox - (concat - (format "\n%s" - "OrgInlineTaskHeading" - (org-e-odt-format-headline--wrap - inlinetask info)) - contents) - nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\"")))))) - -;;;; Italic - -(defun org-e-odt-italic (italic contents info) - "Transcode ITALIC from Org to ODT. -CONTENTS is the text with italic markup. INFO is a plist holding -contextual information." - (format "%s" - "Emphasis" contents)) - - -;;;; Item - -(defun org-e-odt-item (item contents info) - "Transcode an ITEM element from Org to ODT. -CONTENTS holds the contents of the item. INFO is a plist holding -contextual information." - (let* ((plain-list (org-export-get-parent item)) - (type (org-element-property :type plain-list)) - (counter (org-element-property :counter item)) - (tag (let ((tag (org-element-property :tag item))) - (and tag - (concat (org-e-odt--checkbox item) - (org-export-data tag info)))))) - (case type - ((ordered unordered) - (format "\n\n%s\n%s" - contents - (let* ((--element-has-a-table-p - (function - (lambda (element info) - (loop for el in (org-element-contents element) - thereis (eq (org-element-type el) 'table)))))) - (cond - ((funcall --element-has-a-table-p item info) - "") - (t ""))))) - (descriptive - (concat - (let ((term (or tag "(no term)"))) - (concat - (format "\n\n%s\n" - (format "\n%s" - "Text_20_body_20_bold" term)) - (format - "\n\n%s\n" - (format "\n\n%s\n" - "OrgDescriptionList" - "text:continue-numbering=\"false\"" - (format "\n\n%s\n" - contents))))))) - (t (error "Unknown list type: %S" type))))) - - -;;;; Keyword - -(defun org-e-odt-keyword (keyword contents info) - "Transcode a KEYWORD element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (let ((key (org-element-property :key keyword)) - (value (org-element-property :value keyword))) - (cond - ((string= key "LATEX") value) - ((string= key "INDEX") (format "\\index{%s}" value)) - ((string= key "TARGET") nil ; FIXME - ;; (format "\\label{%s}" (org-export-solidify-link-text value)) - ) - ((string= key "toc") - (let ((value (downcase value))) - (cond - ((string-match "\\" value) - (let ((depth (or (and (string-match "[0-9]+" value) - (string-to-number (match-string 0 value))) - (plist-get info :with-toc)))) - (when (wholenump depth) (org-e-odt-toc depth info)))) - ((string= "tables" value) "FIXME") - ((string= "figures" value) "FIXME") - ((string= "listings" value) - (cond - ;; At the moment, src blocks with a caption are wrapped - ;; into a figure environment. - (t "FIXME"))))))))) - - -;;;; Latex Environment - - -(eval-after-load 'org-odt - '(ad-deactivate 'org-format-latex-as-mathml)) - -;; (defadvice org-format-latex-as-mathml ; FIXME -;; (after org-e-odt-protect-latex-fragment activate) -;; "Encode LaTeX fragment as XML. -;; Do this when translation to MathML fails." -;; (when (or (not (> (length ad-return-value) 0)) -;; (get-text-property 0 'org-protected ad-return-value)) -;; (setq ad-return-value -;; (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0)) -;; 'org-protected t)))) - -(defun org-e-odt-format-latex (latex-frag processing-type info) - (let* ((prefix (case processing-type - (dvipng "ltxpng/") - (mathml "ltxmathml/"))) - (input-file (plist-get info :input-file)) - (cache-subdir - (concat prefix (file-name-sans-extension - (file-name-nondirectory input-file)))) - (cache-dir (file-name-directory input-file)) - (display-msg (case processing-type - (dvipng "Creating LaTeX Image...") - (mathml "Creating MathML snippet...")))) - (with-temp-buffer - (insert latex-frag) - (org-format-latex cache-subdir cache-dir nil display-msg - nil nil processing-type) - (buffer-string)))) - -(defun org-e-odt-latex-environment (latex-environment contents info) - "Transcode a LATEX-ENVIRONMENT element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (org-e-odt--wrap-label - latex-environment - (let* ((latex-frag - (org-remove-indentation - (org-element-property :value latex-environment))) - (processing-type (plist-get info :LaTeX-fragments)) - (caption (org-element-property :caption latex-environment)) - (short-caption (and (cdr caption) - (org-export-data (cdr caption) info))) - (caption (and (car caption) (org-export-data (car caption) info))) - (label (org-element-property :name latex-environment)) - (attr nil) ; FIXME - (label (org-element-property :name latex-environment))) - - (when (memq processing-type '(t mathjax)) - (unless (and (fboundp 'org-format-latex-mathml-available-p) - (org-format-latex-mathml-available-p)) - (message "LaTeX to MathML converter not available. Trying dvinpng...") - (setq processing-type 'dvipng))) - - (when (eq processing-type 'dvipng) - (unless (and (org-check-external-command "latex" "" t) - (org-check-external-command "dvipng" "" t)) - (message "LaTeX to PNG converter not available. Using verbatim.") - (setq processing-type 'verbatim))) - - (case processing-type - ((t mathjax) - (org-e-odt-format-formula latex-environment info)) - (dvipng - (format "\n%s" - "Text_20_body" - (org-e-odt-link--inline-image latex-environment info))) - (t (org-e-odt-do-format-code latex-frag)))))) - - -;;;; Latex Fragment - - -;; (when latex-frag ; FIXME -;; (setq href (org-propertize href :title "LaTeX Fragment" -;; :description latex-frag))) -;; handle verbatim -;; provide descriptions - -(defun org-e-odt-latex-fragment (latex-fragment contents info) - "Transcode a LATEX-FRAGMENT object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (let* ((latex-frag (org-element-property :value latex-fragment)) - (processing-type (plist-get info :LaTeX-fragments))) - (cond - ((member processing-type '(t mathjax)) - (org-e-odt-format-formula latex-fragment info)) - ((eq processing-type 'dvipng) - (org-e-odt-link--inline-image latex-fragment info)) - (t (org-e-odt-encode-plain-text latex-frag t))))) - - -;;;; Line Break - -(defun org-e-odt-line-break (line-break contents info) - "Transcode a LINE-BREAK object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - "\n") - - -;;;; Link - - - -;;;; Links :: Generic - -(defun org-e-odt-format-link (desc href &optional suppress-xref) - (cond - ((and (= (string-to-char href) ?#) (not suppress-xref)) - (setq href (substring href 1)) - (let ((xref-format "text")) - (when (numberp desc) - (setq desc (format "%d" desc) xref-format "number")) - (when (listp desc) - (setq desc (mapconcat 'number-to-string desc ".") xref-format "chapter")) - (setq href (concat org-e-odt-bookmark-prefix href)) - (format - "%s" - xref-format href desc))) - ;; (org-lparse-link-description-is-image - ;; (format "\n\n%s\n" - ;; href desc)) - (t (format "%s" - href desc)))) - -(defun org-e-odt-format-internal-link (text href) - (org-e-odt-format-link text (concat "#" href))) - -;;;; Links :: Label references - -(defun org-e-odt-enumerate-element (element info &optional predicate n) - (let* ((--numbered-parent-headline-at-<=-n - (function - (lambda (element n info) - (loop for x in (org-export-get-genealogy element) - thereis (and (eq (org-element-type x) 'headline) - (<= (org-export-get-relative-level x info) n) - (org-export-numbered-headline-p x info) - x))))) - (--enumerate - (function - (lambda (element scope info &optional predicate) - (let ((counter 0)) - (org-element-map - (or scope (plist-get info :parse-tree)) - (org-element-type element) - (lambda (el) - (and (or (not predicate) (funcall predicate el info)) - (incf counter) - (eq element el) - counter)) - info 'first-match))))) - (scope (funcall --numbered-parent-headline-at-<=-n - element (or n org-e-odt-display-outline-level) info)) - (ordinal (funcall --enumerate element scope info predicate)) - (tag - (concat - ;; Section number. - (and scope - (mapconcat 'number-to-string - (org-export-get-headline-number scope info) ".")) - ;; Separator. - (and scope ".") - ;; Ordinal. - (number-to-string ordinal)))) - tag)) - -(defun org-e-odt-format-label (element info op) - (let* ((caption-from - (case (org-element-type element) - (link (org-export-get-parent-element element)) - (t element))) - ;; get label and caption. - (label (org-element-property :name caption-from)) - (caption (org-element-property :caption caption-from)) - (short-caption (cdr caption)) - ;; transcode captions. - (caption (and (car caption) (org-export-data (car caption) info))) - (short-caption (and short-caption - (org-export-data short-caption info)))) - (when (or label caption) - (let* ((default-category - (cond - ((eq (org-element-type element) 'table) - "__Table__") - ((org-e-odt-standalone-image-p element info) - "__Figure__") - ((member (org-element-type element) - '(latex-environment latex-fragment)) - (let ((processing-type (plist-get info :LaTeX-fragments))) - (cond - ((eq processing-type 'dvipng) "__DvipngImage__") - ((eq processing-type 'mathjax) "__MathFormula__") - ((eq processing-type 't) "__MathFormula__") - (t (error "Handle LaTeX:verbatim"))))) - ((eq (org-element-type element) 'src-block) - "__Listing__") - (t (error "Handle enumeration of %S" element)))) - (predicate - (cond - ((member (org-element-type element) - '(table latex-environment src-block)) - nil) - ((org-e-odt-standalone-image-p element info) - 'org-e-odt-standalone-image-p) - (t (error "Handle enumeration of %S" element)))) - (seqno (org-e-odt-enumerate-element - element info predicate)) ; FIXME - ;; handle label props. - (label-props (assoc default-category org-e-odt-category-map-alist)) - ;; identify opendocument counter - (counter (nth 1 label-props)) - ;; identify label style - (label-style (nth 2 label-props)) - ;; retrieve localized category sting - (category (org-export-translate (nth 3 label-props) :utf-8 info))) - (case op - (definition - ;; assign an internal label, if user has not provided one - (setq label (or label (format "%s-%s" default-category seqno))) - (setq label (org-export-solidify-link-text label)) - - (cons - (format-spec - (cadr (assoc-string label-style org-e-odt-label-styles t)) - `((?e . ,category) - (?n . ,(format - "%s" - label counter counter seqno)) - (?c . ,(or caption "")))) - short-caption)) - (reference - (assert label) - (setq label (org-export-solidify-link-text label)) - (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t))) - (fmt1 (car fmt)) - (fmt2 (cadr fmt))) - (format "%s" - fmt1 label (format-spec fmt2 `((?e . ,category) - (?n . ,seqno)))))) - (t (error "Unknow %S on label" op))))))) - -;;;; Links :: Embedded images - -(defun org-e-odt-copy-image-file (path) - "Returns the internal name of the file" - (let* ((image-type (file-name-extension path)) - (media-type (format "image/%s" image-type)) - (target-dir "Images/") - (target-file - (format "%s%04d.%s" target-dir - (incf org-e-odt-embedded-images-count) image-type))) - (message "Embedding %s as %s ..." - (substring-no-properties path) target-file) - - (when (= 1 org-e-odt-embedded-images-count) - (make-directory (concat org-e-odt-zip-dir target-dir)) - (org-e-odt-create-manifest-file-entry "" target-dir)) - - (copy-file path (concat org-e-odt-zip-dir target-file) 'overwrite) - (org-e-odt-create-manifest-file-entry media-type target-file) - target-file)) - -(defun org-e-odt-image-size-from-file (file &optional user-width - user-height scale dpi embed-as) - (let* ((--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)))))) - (dpi (or dpi org-e-odt-pixels-per-inch)) - (anchor-type (or embed-as "paragraph")) - (user-width (and (not scale) user-width)) - (user-height (and (not scale) user-height)) - (size - (and - (not (and user-height user-width)) - (or - ;; Use Imagemagick. - (and (executable-find "identify") - (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))) - ;; Use Emacs. - (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)) - ;; Use hard-coded values. - (cdr (assoc-string anchor-type - org-e-odt-default-image-sizes-alist)) - ;; Error out. - (error "Cannot determine image size, aborting")))) - (width (car size)) (height (cdr size))) - (cond - (scale - (setq width (* width scale) height (* height scale))) - ((and user-height user-width) - (setq width user-width height user-height)) - (user-height - (setq width (* user-height (/ width height)) height user-height)) - (user-width - (setq height (* user-width (/ height width)) width user-width)) - (t (ignore))) - ;; ensure that an embedded image fits comfortably within a page - (let ((max-width (car org-e-odt-max-image-size)) - (max-height (cdr org-e-odt-max-image-size))) - (when (or (> width max-width) (> height max-height)) - (let* ((scale1 (/ max-width width)) - (scale2 (/ max-height height)) - (scale (min scale1 scale2))) - (setq width (* scale width) height (* scale height))))) - (cons width height))) - -;;;; Links :: Math formula - -(defun org-e-odt-format-formula (element info) - (let* ((src (cond - ((eq (org-element-type element) 'link) ; FIXME - (let* ((type (org-element-property :type element)) - (raw-path (org-element-property :path element))) - (cond - ((file-name-absolute-p raw-path) - (expand-file-name raw-path)) - (t raw-path)))) - ((member (org-element-type element) - '(latex-fragment latex-environment)) - (let* ((latex-frag (org-remove-indentation - (org-element-property :value element))) - (formula-link (org-e-odt-format-latex - latex-frag 'mathml info))) - (and formula-link - (string-match "file:\\([^]]*\\)" formula-link) - (match-string 1 formula-link)))) - (t (error "what is this?")))) - (full-src (if (file-name-absolute-p src) src - (expand-file-name src (file-name-directory - (plist-get info :input-file))))) - (caption-from - (case (org-element-type element) - (link (org-export-get-parent-element element)) - (t element))) - (captions (org-e-odt-format-label caption-from info 'definition)) - (caption (car captions)) - (href - (format "\n" - " xlink:show=\"embed\" xlink:actuate=\"onLoad\"" - (file-name-directory (org-e-odt-copy-formula-file full-src)))) - (embed-as (if caption 'paragraph 'character)) - width height) - (cond - ((eq embed-as 'character) - (org-e-odt-format-entity "InlineFormula" href width height)) - (t - (let* ((equation (org-e-odt-format-entity - "CaptionedDisplayFormula" href width height captions)) - (label - (let* ((org-e-odt-category-map-alist - '(("__Table__" "Table" "value") - ("__Figure__" "Illustration" "value") - ("__MathFormula__" "Text" "math-label") - ("__DvipngImage__" "Equation" "value") - ("__Listing__" "Listing" "value")))) - (car (org-e-odt-format-label caption-from info 'definition)))) - (formula-tree - (org-e-odt--adopt-elements - `(table (:type org :attr_odt (":style \"OrgEquation\""))) - (org-e-odt--adopt-elements - `(table-row (:type standard)) - `(table-cell nil "") `(table-cell nil "")) - (org-e-odt--adopt-elements - `(table-row (:type standard)) - (org-e-odt--adopt-elements - `(table-cell nil) `(export-block - (:type "ODT" :value ,equation))) - (org-e-odt--adopt-elements - `(table-cell nil) `(export-block - (:type "ODT" :value ,label)))))) - (formula-info - (org-export-collect-tree-properties - formula-tree (org-export-get-environment 'e-odt)))) - (org-export-data formula-tree formula-info)))))) - -(defun org-e-odt-copy-formula-file (src-file) - "Returns the internal name of the file" - (let* ((target-dir (format "Formula-%04d/" - (incf org-e-odt-embedded-formulas-count))) - (target-file (concat target-dir "content.xml"))) - ;; Create a directory for holding formula file. Also enter it in - ;; to manifest. - (make-directory (concat org-e-odt-zip-dir target-dir)) - (org-e-odt-create-manifest-file-entry - "application/vnd.oasis.opendocument.formula" target-dir "1.2") - ;; Copy over the formula file from user directory to zip - ;; directory. - (message "Embedding %s as %s ..." src-file target-file) - (let ((case-fold-search nil)) - (cond - ;; Case 1: Mathml. - ((string-match "\\.\\(mathml\\|mml\\)\\'" src-file) - (copy-file src-file (concat org-e-odt-zip-dir target-file) 'overwrite)) - ;; Case 2: OpenDocument formula. - ((string-match "\\.odf\\'" src-file) - (org-e-odt--zip-extract src-file "content.xml" - (concat org-e-odt-zip-dir target-dir))) - (t (error "%s is not a formula file" src-file)))) - ;; Enter the formula file in to manifest. - (org-e-odt-create-manifest-file-entry "text/xml" target-file) - target-file)) - -;;;; Targets - -(defun org-e-odt-format-target (text id) - (let ((name (concat org-e-odt-bookmark-prefix id))) - (concat - (and id (format "\n" name)) - (concat (and id (format "\n" id)) text) - (and id (format "\n" name))))) - -(defun org-e-odt-link--inline-image (element info) - "Return HTML code for an inline image. -LINK is the link pointing to the inline image. INFO is a plist -used as a communication channel." - (let* ((src (cond - ((eq (org-element-type element) 'link) - (let* ((type (org-element-property :type element)) - (raw-path (org-element-property :path element))) - (cond ((member type '("http" "https")) - (concat type ":" raw-path)) - ((file-name-absolute-p raw-path) - (expand-file-name raw-path)) - (t raw-path)))) - ((member (org-element-type element) - '(latex-fragment latex-environment)) - (let* ((latex-frag (org-remove-indentation - (org-element-property :value element))) - (formula-link (org-e-odt-format-latex - latex-frag 'dvipng info))) - (and formula-link - (string-match "file:\\([^]]*\\)" formula-link) - (match-string 1 formula-link)))) - (t (error "what is this?")))) - (src-expanded (if (file-name-absolute-p src) src - (expand-file-name src (file-name-directory - (plist-get info :input-file))))) - (href (format - "\n" - (org-e-odt-copy-image-file src-expanded))) - ;; extract attributes from #+ATTR_ODT line. - (attr-from (case (org-element-type element) - (link (org-export-get-parent-element element)) - (t element))) - ;; convert attributes to a plist. - (attr-plist (org-export-read-attribute :attr_odt attr-from)) - ;; handle `:anchor', `:style' and `:attributes' properties. - (user-frame-anchor - (car (assoc-string (plist-get attr-plist :anchor) - '(("as-char") ("paragraph") ("page")) t))) - (user-frame-style - (and user-frame-anchor (plist-get attr-plist :style))) - (user-frame-attrs - (and user-frame-anchor (plist-get attr-plist :attributes))) - (user-frame-params - (list user-frame-style user-frame-attrs user-frame-anchor)) - ;; (embed-as (or embed-as user-frame-anchor "paragraph")) - ;; extrac - ;; handle `:width', `:height' and `:scale' properties. - (size (org-e-odt-image-size-from-file - src-expanded (plist-get attr-plist :width) - (plist-get attr-plist :height) - (plist-get attr-plist :scale) nil ;; embed-as - "paragraph" ; FIXME - )) - (width (car size)) (height (cdr size)) - (embed-as - (case (org-element-type element) - ((org-e-odt-standalone-image-p element info) "paragraph") - (latex-fragment "as-char") - (latex-environment "paragraph") - (t "paragraph"))) - (captions (org-e-odt-format-label element info 'definition)) - (caption (car captions)) (short-caption (cdr captions)) - (entity (concat (and caption "Captioned") embed-as "Image"))) - (org-e-odt-format-entity entity href width height - captions user-frame-params ))) - -(defun org-e-odt-format-entity (entity href width height &optional - captions user-frame-params) - (let* ((caption (car captions)) (short-caption (cdr captions)) - (entity-style (assoc-string entity org-e-odt-entity-frame-styles t)) - default-frame-params frame-params - (--merge-frame-params - (function - (lambda (default-frame-params user-frame-params) - (if (not user-frame-params) default-frame-params - (assert (= (length default-frame-params) 3)) - (assert (= (length user-frame-params) 3)) - (loop for user-frame-param in user-frame-params - for default-frame-param in default-frame-params - collect (or user-frame-param default-frame-param))))))) - (cond - ((not caption) - (setq default-frame-params (nth 2 entity-style)) - (setq frame-params (funcall --merge-frame-params - default-frame-params user-frame-params)) - (apply 'org-e-odt--frame href width height frame-params)) - (t - (setq default-frame-params (nth 3 entity-style)) - (setq frame-params (funcall --merge-frame-params - default-frame-params user-frame-params)) - (apply 'org-e-odt--textbox - (format "\n%s" - "Illustration" - (concat - (apply 'org-e-odt--frame href width height - (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)) - caption)) - width height frame-params))))) - -(defun org-e-odt-standalone-image-p (element info) - "Test if ELEMENT is a standalone image for the purpose ODT export. -INFO is a plist holding contextual information. - -Return non-nil, if ELEMENT is of type paragraph and it's sole -content, save for whitespaces, is a link that qualifies as an -inline image. - -Return non-nil, if ELEMENT is of type link and it's containing -paragraph has no other content save for leading and trailing -whitespaces. - -Return nil, otherwise. - -Bind `org-e-odt-standalone-image-predicate' to constrain -paragraph further. For example, to check for only captioned -standalone images, do the following. - - \(setq org-e-odt-standalone-image-predicate - \(lambda \(paragraph\) - \(org-element-property :caption paragraph\)\)\) -" - (let ((--standalone-image-predicate - (function (lambda (paragraph) - (or (org-element-property :caption paragraph) - (org-element-property :name paragraph))))) - (paragraph (case (org-element-type element) - (paragraph element) - (link (and (org-export-inline-image-p - element org-e-odt-inline-image-rules) - (org-export-get-parent element))) - (t nil)))) - (when paragraph - (assert (eq (org-element-type paragraph) 'paragraph)) - (when (funcall --standalone-image-predicate paragraph) - (let ((contents (org-element-contents paragraph))) - (loop for x in contents - with inline-image-count = 0 - always (cond - ((eq (org-element-type x) 'plain-text) - (not (org-string-nw-p x))) - ((eq (org-element-type x) 'link) - (when (org-export-inline-image-p - x org-e-odt-inline-image-rules) - (= (incf inline-image-count) 1))) - (t nil)))))))) - -(defun org-e-odt-link (link desc info) - "Transcode a LINK object from Org to ODT. - -DESC is the description part of the link, or the empty string. -INFO is a plist holding contextual information. See -`org-export-data'." - (let* ((type (org-element-property :type link)) - (raw-path (org-element-property :path link)) - ;; Ensure DESC really exists, or set it to nil. - (desc (and (not (string= desc "")) desc)) - (imagep (org-export-inline-image-p - link org-e-odt-inline-image-rules)) - (path (cond - ((member type '("http" "https" "ftp" "mailto")) - (concat type ":" raw-path)) - ((string= type "file") - (when (string-match "\\(.+\\)::.+" raw-path) - (setq raw-path (match-string 1 raw-path))) - (if (file-name-absolute-p raw-path) - (concat "file://" (expand-file-name raw-path)) - (concat "file://" raw-path))) - (t raw-path))) - protocol) - (cond - ;; Image file. - ((and (not desc) (org-export-inline-image-p - link org-e-odt-inline-image-rules)) - (org-e-odt-link--inline-image link info)) - ;; Radio target: Transcode target's contents and use them as - ;; link's description. - ((string= type "radio") - (let ((destination (org-export-resolve-radio-link link info))) - (when destination - (org-e-odt-format-internal-link - (org-export-data (org-element-contents destination) info) - (org-export-solidify-link-text path))))) - ;; Links pointing to an headline: Find destination and build - ;; appropriate referencing command. - ((member type '("custom-id" "fuzzy" "id")) - (let ((destination (if (string= type "fuzzy") - (org-export-resolve-fuzzy-link link info) - (org-export-resolve-id-link link info)))) - (case (org-element-type destination) - ;; Fuzzy link points nowhere. - ('nil - (format "%s" - "Emphasis" (or desc (org-export-data - (org-element-property - :raw-link link) info)))) - ;; Fuzzy link points to an invisible target. - (keyword nil) - ;; LINK points to an headline. Check if LINK should display - ;; section numbers. - (headline - (let* ((headline-no (org-export-get-headline-number destination info)) - (label (format "sec-%s" (mapconcat 'number-to-string - headline-no "-"))) - (desc - ;; Case 1: Headline is numbered and LINK has no - ;; description or LINK's description matches - ;; headline's title. Display section number. - (if (and (org-export-numbered-headline-p destination info) - (or (not desc) - (string= desc (org-element-property - :raw-value destination)))) - headline-no - ;; Case 2: Either the headline is un-numbered or - ;; LINK has a custom description. Display LINK's - ;; description or headline's title. - (or desc (org-export-data (org-element-property - :title destination) info))))) - (org-e-odt-format-internal-link desc label))) - ;; Fuzzy link points to a target. Do as above. - (otherwise - ;; (unless desc - ;; (setq number (cond - ;; ((org-e-odt-standalone-image-p destination info) - ;; (org-export-get-ordinal - ;; (assoc 'link (org-element-contents destination)) - ;; info 'link 'org-e-odt-standalone-image-p)) - ;; (t (org-export-get-ordinal destination info)))) - ;; (setq desc (when number - ;; (if (atom number) (number-to-string number) - ;; (mapconcat 'number-to-string number "."))))) - - (let ((label-reference - (org-e-odt-format-label destination info 'reference))) - (assert label-reference) - label-reference))))) - ;; Coderef: replace link with the reference name or the - ;; equivalent line number. - ((string= type "coderef") - (let* ((fmt (org-export-get-coderef-format path desc)) - (res (org-export-resolve-coderef path info)) - (href (concat "#coderef-" path))) - (format fmt (org-e-odt-format-link res href)))) - ;; Link type is handled by a special function. - ((functionp (setq protocol (nth 2 (assoc type org-link-protocols)))) - (funcall protocol (org-link-unescape path) desc 'odt)) - ;; External link with a description part. - ((and path desc) (org-e-odt-format-link desc path)) - ;; External link without a description part. - (path (org-e-odt-format-link path path)) - ;; No path, only description. Try to do something useful. - (t (format "%s" - "Emphasis" desc))))) - - -;;;; Babel Call - -;; Babel Calls are ignored. - - -;;;; Macro - -(defun org-e-odt-macro (macro contents info) - "Transcode a MACRO element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - ;; Use available tools. - (org-export-expand-macro macro info)) - - -;;;; Paragraph - -(defun org-e-odt-paragraph (paragraph contents info) - "Transcode a PARAGRAPH element from Org to ODT. -CONTENTS is the contents of the paragraph, as a string. INFO is -the plist used as a communication channel." - (let* ((parent (org-export-get-parent paragraph)) - (parent-type (org-element-type parent)) - (style (case parent-type - (quote-block "Quotations") - (center-block "OrgCenter") - (footnote-definition "Footnote") - (t "Text_20_body")))) - ;; If this paragraph is a leading paragraph in a non-descriptive - ;; item and the item has a checkbox, splice the checkbox and - ;; paragraph contents together. - (when (and (eq (org-element-type parent) 'item) - (not (eq (org-element-property :type - (org-export-get-parent parent)) - 'descriptive)) - (eq paragraph (car (org-element-contents parent)))) - (setq contents (concat (org-e-odt--checkbox parent) contents))) - (assert style) - (format "\n%s" style contents))) - - -;;;; Plain List - -(defun org-e-odt-plain-list (plain-list contents info) - "Transcode a PLAIN-LIST element from Org to ODT. -CONTENTS is the contents of the list. INFO is a plist holding -contextual information." - (let* ((type (org-element-property :type plain-list)) - (continue-numbering nil)) - (assert (member type '(ordered unordered descriptive))) - (org-e-odt--wrap-label - plain-list - (format "\n\n%s" - (assoc-default type '((ordered . "OrgNumberedList") - (unordered . "OrgBulletedList") - (descriptive . "OrgDescriptionList"))) - ;; If top-level list, re-start numbering. Otherwise, - ;; continue numbering. - (format "text:continue-numbering=\"%s\"" - (let* ((parent (org-export-get-parent plain-list))) - (if (and parent (eq (org-element-type parent) 'item)) - "true" "false"))) - contents)))) - -;;;; Plain Text - -(defun org-e-odt-fill-tabs-and-spaces (line) - (replace-regexp-in-string - "\\([\t]\\|\\([ ]+\\)\\)" - (lambda (s) - (cond - ((string= s "\t") "") - (t (let ((n (length s))) - (cond - ((= n 1) " ") - ((> n 1) (concat " " (format "" (1- n)))) - (t "")))))) - line)) - -(defun org-e-odt-encode-plain-text (text &optional no-whitespace-filling) - (mapc - (lambda (pair) - (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t))) - '(("&" . "&") ("<" . "<") (">" . ">"))) - (if no-whitespace-filling text - (org-e-odt-fill-tabs-and-spaces text))) - -(defun org-e-odt--quotation-marks (text info) - "Export quotation marks depending on language conventions. -TEXT is a string containing quotation marks to be replaced. INFO -is a plist used as a communication channel." - (mapc (lambda(l) - (let ((start 0)) - (while (setq start (string-match (car l) text start)) - (let ((new-quote (concat (match-string 1 text) (cdr l)))) - (setq text (replace-match new-quote t t text)))))) - (cdr (or (assoc (plist-get info :language) org-e-odt-quotes) - ;; Falls back on English. - (assoc "en" org-e-odt-quotes)))) - text) - -(defun org-e-odt-plain-text (text info) - "Transcode a TEXT string from Org to ODT. -TEXT is the string to transcode. INFO is a plist holding -contextual information." - ;; Protect &, < and >. - (setq text (org-e-odt-encode-plain-text text t)) - ;; Handle quotation marks - (setq text (org-e-odt--quotation-marks text info)) - ;; Convert special strings. - (when (plist-get info :with-special-strings) - (mapc - (lambda (pair) - (setq text (replace-regexp-in-string (car pair) (cdr pair) text t nil))) - org-e-odt-special-string-regexps)) - ;; Handle break preservation if required. - (when (plist-get info :preserve-breaks) - (setq text (replace-regexp-in-string - "\\(\\\\\\\\\\)?[ \t]*\n" "\n" text t))) - ;; Return value. - text) - - -;;;; Planning - -(defun org-e-odt-planning (planning contents info) - "Transcode a PLANNING element from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (format "%s" - "OrgTimestampWrapper" - (concat - (let ((closed (org-element-property :closed planning))) - (when closed - (concat - (format "%s" - "OrgTimestampKeyword" org-closed-string) - (format "%s" - "OrgTimestamp" (org-translate-time closed))))) - (let ((deadline (org-element-property :deadline planning))) - (when deadline - (concat - (format "%s" - "OrgTimestampKeyword" org-deadline-string) - (format "%s" - "OrgTimestamp" (org-translate-time deadline))))) - (let ((scheduled (org-element-property :scheduled planning))) - (when scheduled - (concat - (format "%s" - "OrgTimestampKeyword" org-scheduled-string) - (format "%s" - "OrgTimestamp" (org-translate-time scheduled)))))))) - - -;;;; Property Drawer - -(defun org-e-odt-property-drawer (property-drawer contents info) - "Transcode a PROPERTY-DRAWER element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual -information." - ;; The property drawer isn't exported but we want separating blank - ;; lines nonetheless. - "") - - -;;;; Quote Block - -(defun org-e-odt-quote-block (quote-block contents info) - "Transcode a QUOTE-BLOCK element from Org to ODT. -CONTENTS holds the contents of the block. INFO is a plist -holding contextual information." - (org-e-odt--wrap-label quote-block contents)) - - -;;;; Quote Section - -(defun org-e-odt-quote-section (quote-section contents info) - "Transcode a QUOTE-SECTION element from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (let ((value (org-remove-indentation - (org-element-property :value quote-section)))) - (when value (org-e-odt-do-format-code value)))) - - -;;;; Section - - -(defun org-e-odt-format-section (text style &optional name) - (let ((default-name (car (org-e-odt-add-automatic-style "Section")))) - (format "\n\n%s" - style - (format "text:name=\"%s\"" (or name default-name)) - text))) - - -(defun org-e-odt-section (section contents info) ; FIXME - "Transcode a SECTION element from Org to ODT. -CONTENTS holds the contents of the section. INFO is a plist -holding contextual information." - contents) - -;;;; Radio Target - -(defun org-e-odt-radio-target (radio-target text info) - "Transcode a RADIO-TARGET object from Org to ODT. -TEXT is the text of the target. INFO is a plist holding -contextual information." - (org-e-odt-format-target - text (org-export-solidify-link-text - (org-element-property :value radio-target)))) - - -;;;; Special Block - -(defun org-e-odt-special-block (special-block contents info) - "Transcode a SPECIAL-BLOCK element from Org to ODT. -CONTENTS holds the contents of the block. INFO is a plist -holding contextual information." - (let ((type (downcase (org-element-property :type special-block))) - (attributes (org-export-read-attribute :attr_odt special-block))) - (org-e-odt--wrap-label - special-block - (cond - ;; Annotation. - ((string= type "annotation") - (let ((author (or (plist-get attributes :author) - (let ((author (plist-get info :author))) - (and author (org-export-data author info))))) - (date (or (plist-get attributes :date) - (plist-get info :date)))) - - (format "\n%s" - "Text_20_body" - (format "\n%s\n" - (concat - (and author - (format "%s" author)) - (and date - (format "%s" - (org-e-odt--date date))) - contents))))) - ;; Textbox. - ((string= type "textbox") - (let ((width (plist-get attributes :width)) - (height (plist-get attributes :height)) - (style (plist-get attributes :style)) - (extra (plist-get attributes :extra)) - (anchor (plist-get attributes :anchor))) - (format "\n%s" - "Text_20_body" (org-e-odt--textbox contents width height - style extra anchor)))) - (t contents))))) - - -;;;; Src Block - - -(defun org-e-odt-hfy-face-to-css (fn) - "Create custom style for face FN. -When FN is the default face, use it's foreground and background -properties to create \"OrgSrcBlock\" paragraph style. Otherwise -use it's color attribute to create a character style whose name -is obtained from FN. Currently all attributes of FN other than -color are ignored. - -The style name for a face FN is derived using the following -operations on the face name in that order - de-dash, CamelCase -and prefix with \"OrgSrc\". For example, -`font-lock-function-name-face' is associated with -\"OrgSrcFontLockFunctionNameFace\"." - (let* ((css-list (hfy-face-to-style fn)) - (style-name ((lambda (fn) - (concat "OrgSrc" - (mapconcat - 'capitalize (split-string - (hfy-face-or-def-to-name fn) "-") - ""))) fn)) - (color-val (cdr (assoc "color" css-list))) - (background-color-val (cdr (assoc "background" css-list))) - (style (and org-e-odt-create-custom-styles-for-srcblocks - (cond - ((eq fn 'default) - (format org-e-odt-src-block-paragraph-format - background-color-val color-val)) - (t - (format - " - - - " style-name color-val)))))) - (cons style-name style))) - -(defun org-e-odt-htmlfontify-string (line) - (let* ((hfy-html-quote-regex "\\([<\"&> ]\\)") - (hfy-html-quote-map '(("\"" """) - ("<" "<") - ("&" "&") - (">" ">") - (" " "") - (" " ""))) - (hfy-face-to-css 'org-e-odt-hfy-face-to-css) - (hfy-optimisations-1 (copy-seq hfy-optimisations)) - (hfy-optimisations (add-to-list 'hfy-optimisations-1 - 'body-text-only)) - (hfy-begin-span-handler - (lambda (style text-block text-id text-begins-block-p) - (insert (format "" style)))) - (hfy-end-span-handler (lambda nil (insert "")))) - (with-no-warnings (htmlfontify-string line)))) - -(defun org-e-odt-do-format-code - (code &optional lang refs retain-labels num-start) - (let* ((lang (or (assoc-default lang org-src-lang-modes) lang)) - (lang-mode (and lang (intern (format "%s-mode" lang)))) - (code-lines (org-split-string code "\n")) - (code-length (length code-lines)) - (use-htmlfontify-p (and (functionp lang-mode) - org-e-odt-fontify-srcblocks - (require 'htmlfontify nil t) - (fboundp 'htmlfontify-string))) - (code (if (not use-htmlfontify-p) code - (with-temp-buffer - (insert code) - (funcall lang-mode) - (font-lock-fontify-buffer) - (buffer-string)))) - (fontifier (if use-htmlfontify-p 'org-e-odt-htmlfontify-string - 'org-e-odt-encode-plain-text)) - (par-style (if use-htmlfontify-p "OrgSrcBlock" - "OrgFixedWidthBlock")) - (i 0)) - (assert (= code-length (length (org-split-string code "\n")))) - (setq code - (org-export-format-code - code - (lambda (loc line-num ref) - (setq par-style - (concat par-style (and (= (incf i) code-length) "LastLine"))) - - (setq loc (concat loc (and ref retain-labels (format " (%s)" ref)))) - (setq loc (funcall fontifier loc)) - (when ref - (setq loc (org-e-odt-format-target loc (concat "coderef-" ref)))) - (assert par-style) - (setq loc (format "\n%s" - par-style loc)) - (if (not line-num) loc - (format "\n%s\n" loc))) - num-start refs)) - (cond - ((not num-start) code) - ((= num-start 0) - (format - "\n%s" - " text:continue-numbering=\"false\"" code)) - (t - (format - "\n%s" - " text:continue-numbering=\"true\"" code))))) - -(defun org-e-odt-format-code (element info) - (let* ((lang (org-element-property :language element)) - ;; Extract code and references. - (code-info (org-export-unravel-code element)) - (code (car code-info)) - (refs (cdr code-info)) - ;; Does the src block contain labels? - (retain-labels (org-element-property :retain-labels element)) - ;; Does it have line numbers? - (num-start (case (org-element-property :number-lines element) - (continued (org-export-get-loc element info)) - (new 0)))) - (org-e-odt-do-format-code code lang refs retain-labels num-start))) - -(defun org-e-odt-src-block (src-block contents info) - "Transcode a SRC-BLOCK element from Org to ODT. -CONTENTS holds the contents of the item. INFO is a plist holding -contextual information." - (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (short-caption (and (cdr caption) - (org-export-data (cdr caption) info))) - (caption (and (car caption) (org-export-data (car caption) info))) - (label (org-element-property :name src-block)) - (attributes (org-export-read-attribute :attr_odt src-block))) - ;; FIXME: Handle caption - ;; caption-str (when caption) - ;; (main (org-export-data (car caption) info)) - ;; (secondary (org-export-data (cdr caption) info)) - ;; (caption-str (org-e-odt--caption/label-string caption label info)) - (let* ((captions (org-e-odt-format-label src-block info 'definition)) - (caption (car captions)) (short-caption (cdr captions))) - (concat - (and caption - (format "\n%s" - "Listing" caption)) - (let ((--src-block (org-e-odt-format-code src-block info))) - (if (not (plist-get attributes :textbox)) --src-block - (format "\n%s" - "Text_20_body" - (org-e-odt--textbox --src-block nil nil nil)))))))) - - -;;;; Statistics Cookie - -(defun org-e-odt-statistics-cookie (statistics-cookie contents info) - "Transcode a STATISTICS-COOKIE object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual information." - (let ((cookie-value (org-element-property :value statistics-cookie))) - (format "%s" - "OrgCode" cookie-value))) - - -;;;; Strike-Through - -(defun org-e-odt-strike-through (strike-through contents info) - "Transcode STRIKE-THROUGH from Org to ODT. -CONTENTS is the text with strike-through markup. INFO is a plist -holding contextual information." - (format "%s" - "Strikethrough" contents)) - - -;;;; Subscript - -(defun org-e-odt-subscript (subscript contents info) - "Transcode a SUBSCRIPT object from Org to ODT. -CONTENTS is the contents of the object. INFO is a plist holding -contextual information." - (format "%s" - "OrgSubscript" contents)) - - -;;;; Superscript - -(defun org-e-odt-superscript (superscript contents info) - "Transcode a SUPERSCRIPT object from Org to ODT. -CONTENTS is the contents of the object. INFO is a plist holding -contextual information." - (format "%s" - "OrgSuperscript" contents)) - - -;;;; Table Cell - -(defun org-e-odt-table-style-spec (element info) - (let* ((table (org-export-get-parent-table element)) - (table-attributes (org-export-read-attribute :attr_odt table)) - (table-style (plist-get table-attributes :style))) - (assoc table-style org-e-odt-table-styles))) - -(defun org-e-odt-get-table-cell-styles (table-cell info) - "Retrieve styles applicable to a table cell. -R and C are (zero-based) row and column numbers of the table -cell. STYLE-SPEC is an entry in `org-e-odt-table-styles' -applicable to the current table. It is `nil' if the table is not -associated with any style attributes. - -Return a cons of (TABLE-CELL-STYLE-NAME . PARAGRAPH-STYLE-NAME). - -When STYLE-SPEC is nil, style the table cell the conventional way -- choose cell borders based on row and column groupings and -choose paragraph alignment based on `org-col-cookies' text -property. See also -`org-e-odt-get-paragraph-style-cookie-for-table-cell'. - -When STYLE-SPEC is non-nil, ignore the above cookie and return -styles congruent with the ODF-1.2 specification." - (let* ((table-cell-address (org-export-table-cell-address table-cell info)) - (r (car table-cell-address)) (c (cdr table-cell-address)) - (style-spec (org-e-odt-table-style-spec table-cell info)) - (table-dimensions (org-export-table-dimensions - (org-export-get-parent-table table-cell) - info))) - (when style-spec - ;; LibreOffice - particularly the Writer - honors neither table - ;; templates nor custom table-cell styles. Inorder to retain - ;; inter-operability with LibreOffice, only automatic styles are - ;; used for styling of table-cells. The current implementation is - ;; congruent with ODF-1.2 specification and hence is - ;; future-compatible. - - ;; 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 - ;; by hand. - (let* ((template-name (nth 1 style-spec)) - (cell-style-selectors (nth 2 style-spec)) - (cell-type - (cond - ((and (cdr (assoc 'use-first-column-styles cell-style-selectors)) - (= c 0)) "FirstColumn") - ((and (cdr (assoc 'use-last-column-styles cell-style-selectors)) - (= (1+ c) (cdr table-dimensions))) - "LastColumn") - ((and (cdr (assoc 'use-first-row-styles cell-style-selectors)) - (= r 0)) "FirstRow") - ((and (cdr (assoc 'use-last-row-styles cell-style-selectors)) - (= (1+ r) (car table-dimensions))) - "LastRow") - ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors)) - (= (% r 2) 1)) "EvenRow") - ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors)) - (= (% r 2) 0)) "OddRow") - ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors)) - (= (% c 2) 1)) "EvenColumn") - ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors)) - (= (% c 2) 0)) "OddColumn") - (t "")))) - (concat template-name cell-type))))) - -(defun org-e-odt-table-cell (table-cell contents info) - "Transcode a TABLE-CELL element from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (let* ((table-cell-address (org-export-table-cell-address table-cell info)) - (r (car table-cell-address)) - (c (cdr table-cell-address)) - (horiz-span (or (org-export-table-cell-width table-cell info) 0)) - (table-row (org-export-get-parent table-cell)) - (custom-style-prefix (org-e-odt-get-table-cell-styles - table-cell info)) - (paragraph-style - (or - (and custom-style-prefix - (format "%sTableParagraph" custom-style-prefix)) - (concat - (cond - ((and (= 1 (org-export-table-row-group table-row info)) - (org-export-table-has-header-p - (org-export-get-parent-table table-row) info)) - "OrgTableHeading") - ((let* ((table (org-export-get-parent-table table-cell)) - (table-attrs (org-export-read-attribute :attr_odt table)) - (table-header-columns (plist-get table-attrs - :header-columns))) - (<= c (cond ((wholenump table-header-columns) - (- table-header-columns 1)) - (table-header-columns 0) - (t -1)))) - "OrgTableHeading") - (t "OrgTableContents")) - (capitalize (symbol-name (org-export-table-cell-alignment - table-cell info)))))) - (cell-style-name - (or - (and custom-style-prefix (format "%sTableCell" - custom-style-prefix)) - (concat - "OrgTblCell" - (when (or (org-export-table-row-starts-rowgroup-p table-row info) - (zerop r)) "T") - (when (org-export-table-row-ends-rowgroup-p table-row info) "B") - (when (and (org-export-table-cell-starts-colgroup-p table-cell info) - (not (zerop c)) ) "L")))) - (cell-attributes - (concat - (format " table:style-name=\"%s\"" cell-style-name) - (and (> horiz-span 0) - (format " table:number-columns-spanned=\"%d\"" - (1+ horiz-span)))))) - (unless contents (setq contents "")) - (concat - (assert paragraph-style) - (format "\n\n%s\n" - cell-attributes - (format "\n%s" - paragraph-style contents)) - (let (s) - (dotimes (i horiz-span s) - (setq s (concat s "\n")))) - "\n"))) - - -;;;; Table Row - -(defun org-e-odt-table-row (table-row contents info) - "Transcode a TABLE-ROW element from Org to ODT. -CONTENTS is the contents of the row. INFO is a plist used as a -communication channel." - ;; Rules are ignored since table separators are deduced from - ;; borders of the current row. - (when (eq (org-element-property :type table-row) 'standard) - (let* ((rowgroup-tags - (if (and (= 1 (org-export-table-row-group table-row info)) - (org-export-table-has-header-p - (org-export-get-parent-table table-row) info)) - ;; If the row belongs to the first rowgroup and the - ;; table has more than one row groups, then this row - ;; belongs to the header row group. - '("\n" . "\n") - ;; Otherwise, it belongs to non-header row group. - '("\n" . "\n")))) - (concat - ;; Does this row begin a rowgroup? - (when (org-export-table-row-starts-rowgroup-p table-row info) - (car rowgroup-tags)) - ;; Actual table row - (format "\n\n%s\n" contents) - ;; Does this row end a rowgroup? - (when (org-export-table-row-ends-rowgroup-p table-row info) - (cdr rowgroup-tags)))))) - - -;;;; Table - -(defun org-e-odt-table-first-row-data-cells (table info) - (let ((table-row - (org-element-map - table 'table-row - (lambda (row) - (unless (eq (org-element-property :type row) 'rule) row)) - info 'first-match)) - (special-column-p (org-export-table-has-special-column-p table))) - (if (not special-column-p) (org-element-contents table-row) - (cdr (org-element-contents table-row))))) - -(defun org-e-odt--table (table contents info) - "Transcode a TABLE element from Org to ODT. -CONTENTS is the contents of the table. INFO is a plist holding -contextual information." - (case (org-element-property :type table) - ;; Case 1: table.el doesn't support export to OD format. Strip - ;; such tables from export. - (table.el - (prog1 nil - (message - (concat - "(org-e-odt): Found table.el-type table in the source Org file." - " table.el doesn't support export to ODT format." - " Stripping the table from export.")))) - ;; Case 2: Native Org tables. - (otherwise - (let* ((captions (org-e-odt-format-label table info 'definition)) - (caption (car captions)) (short-caption (cdr captions)) - (attributes (org-export-read-attribute :attr_odt table)) - (custom-table-style (nth 1 (org-e-odt-table-style-spec table info))) - (table-column-specs - (function - (lambda (table info) - (let* ((table-style (or custom-table-style "OrgTable")) - (column-style (format "%sColumn" table-style))) - (mapconcat - (lambda (table-cell) - (let ((width (1+ (or (org-export-table-cell-width - table-cell info) 0))) - (s (format - "\n" - column-style)) - out) - (dotimes (i width out) (setq out (concat s out))))) - (org-e-odt-table-first-row-data-cells table info) "\n")))))) - (concat - ;; caption. - (when caption - (format "\n%s" - "Table" caption)) - ;; begin table. - (let* ((automatic-name - (org-e-odt-add-automatic-style "Table" attributes))) - (format - "\n" - (or short-caption (car automatic-name)) - (or custom-table-style (cdr automatic-name) "OrgTable"))) - ;; column specification. - (funcall table-column-specs table info) - ;; actual contents. - "\n" contents - ;; end table. - ""))))) - -(defun org-e-odt-table (table contents info) - "Transcode a TABLE element from Org to ODT. -CONTENTS is the contents of the table. INFO is a plist holding -contextual information." - (let* ((--get-previous-elements - (function - (lambda (blob info) - (let ((parent (org-export-get-parent blob))) - (cdr (member blob (reverse (org-element-contents parent)))))))) - (--element-preceded-by-table-p - (function - (lambda (element info) - (loop for el in (funcall --get-previous-elements element info) - thereis (eq (org-element-type el) 'table))))) - (--walk-list-genealogy-and-collect-tags - (function - (lambda (table info) - (let* ((genealogy (org-export-get-genealogy table)) - (list-genealogy - (when (eq (org-element-type (car genealogy)) 'item) - (loop for el in genealogy - when (member (org-element-type el) - '(item plain-list)) - collect el)))) - (loop for el in list-genealogy - with parent-list collect - (case (org-element-type el) - (plain-list - (setq parent-list el) - `("" - . ,(let ((type (org-element-property :type el))) - (format - "" - (assoc-default - type '((ordered . "OrgNumberedList") - (unordered . "OrgBulletedList") - (descriptive . "OrgDescriptionList"))) - "text:continue-numbering=\"true\"")))) - (item - (cond - ((not parent-list) - (if (funcall --element-preceded-by-table-p table info) - '("" . "") - '("" . ""))) - ((funcall --element-preceded-by-table-p - parent-list info) - '("" . "")) - (t '("" . "")))))))))) - (close-open-tags (funcall --walk-list-genealogy-and-collect-tags - table info))) - ;; OpenDocument schema does not permit table to occur within a - ;; list item. So, to typeset an indented table, we make use of - ;; list continuations. - (concat "\n" - ;; Discontinue the list. - (mapconcat 'car close-open-tags "\n") - ;; Put the table in an indented section. - (let* ((table (org-e-odt--table table contents info)) - (level (/ (length (mapcar 'car close-open-tags)) 2)) - (style (format "OrgIndentedSection-Level-%d" level))) - (when table (org-e-odt-format-section table style))) - ;; Continue the list. - (mapconcat 'cdr (nreverse close-open-tags) "\n")))) - - -;;;; Target - -(defun org-e-odt-target (target contents info) - "Transcode a TARGET object from Org to ODT. -CONTENTS is nil. INFO is a plist holding contextual -information." - (org-e-odt-format-target - "" (org-export-solidify-link-text (org-element-property :value target)))) - - -;;;; Timestamp - -(defun org-e-odt-timestamp (timestamp contents info) - "Transcode a TIMESTAMP object from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (let ((timestamp-1 (org-element-property :value timestamp)) - (timestamp-2 (org-element-property :range-end timestamp))) - (format "%s" - "OrgTimestampWrapper" - (concat - (format "%s" - "OrgTimestamp" (org-translate-time timestamp-1)) - (and timestamp-2 - "–" - (format "%s" - "OrgTimestamp" (org-translate-time timestamp-2))))))) - - -;;;; Underline - -(defun org-e-odt-underline (underline contents info) - "Transcode UNDERLINE from Org to ODT. -CONTENTS is the text with underline markup. INFO is a plist -holding contextual information." - (format "%s" - "Underline" contents)) - - -;;;; Verbatim - -(defun org-e-odt-verbatim (verbatim contents info) - "Transcode a VERBATIM object from Org to ODT. -CONTENTS is nil. INFO is a plist used as a communication -channel." - (format "%s" - "OrgCode" (org-element-property :value verbatim))) - - -;;;; Verse Block - -(defun org-e-odt-verse-block (verse-block contents info) - "Transcode a VERSE-BLOCK element from Org to ODT. -CONTENTS is verse block contents. INFO is a plist holding -contextual information." - ;; Add line breaks to each line of verse. - (setq contents (replace-regexp-in-string - "\\(\\)?[ \t]*\n" - "" contents)) - ;; Replace tabs and spaces. - (setq contents (org-e-odt-fill-tabs-and-spaces contents)) - ;; Surround it in a verse environment. - (org-e-odt--wrap-label - verse-block - (format "\n%s" - "OrgVerse" contents))) - - - - - -;;; Interactive functions - -(defun org-e-odt-create-manifest-file-entry (&rest args) - (push args org-e-odt-manifest-file-entries)) - -(defun org-e-odt-write-manifest-file () - (make-directory (concat org-e-odt-zip-dir "META-INF")) - (let ((manifest-file (concat org-e-odt-zip-dir "META-INF/manifest.xml"))) - (with-current-buffer - (let ((nxml-auto-insert-xml-declaration-flag nil)) - (find-file-noselect manifest-file t)) - (insert - " - \n") - (mapc - (lambda (file-entry) - (let* ((version (nth 2 file-entry)) - (extra (if (not version) "" - (format " manifest:version=\"%s\"" version)))) - (insert - (format org-e-odt-manifest-file-entry-tag - (nth 0 file-entry) (nth 1 file-entry) extra)))) - org-e-odt-manifest-file-entries) - (insert "\n")))) - -(defmacro org-e-odt--export-wrap (out-file &rest body) - `(let* ((--out-file ,out-file) - (out-file-type (file-name-extension --out-file)) - (org-e-odt-xml-files '("META-INF/manifest.xml" "content.xml" - "meta.xml" "styles.xml")) - ;; Initialize workarea. All files that end up in the - ;; exported get created here. - (org-e-odt-zip-dir (file-name-as-directory - (make-temp-file (format "%s-" out-file-type) t))) - (org-e-odt-manifest-file-entries nil) - (--cleanup-xml-buffers - (function - (lambda nil - ;; Kill all XML buffers. - (mapc (lambda (file) - (let ((buf (get-file-buffer - (concat org-e-odt-zip-dir file)))) - (when buf - (set-buffer-modified-p nil) - (kill-buffer buf)))) - org-e-odt-xml-files) - ;; Delete temporary directory and also other embedded - ;; files that get copied there. - (delete-directory org-e-odt-zip-dir t))))) - (org-condition-case-unless-debug - err - (progn - (unless (executable-find "zip") - ;; Not at all OSes ship with zip by default - (error "Executable \"zip\" needed for creating OpenDocument files")) - ;; Do export. This creates a bunch of xml files ready to be - ;; saved and zipped. - (progn ,@body) - ;; Create a manifest entry for content.xml. - (org-e-odt-create-manifest-file-entry "text/xml" "content.xml") - - ;; Write mimetype file - (let* ((mimetypes - '(("odt" . "application/vnd.oasis.opendocument.text") - ("odf" . "application/vnd.oasis.opendocument.formula"))) - (mimetype (cdr (assoc-string out-file-type mimetypes t)))) - (unless mimetype - (error "Unknown OpenDocument backend %S" out-file-type)) - (write-region mimetype nil (concat org-e-odt-zip-dir "mimetype")) - (org-e-odt-create-manifest-file-entry mimetype "/" "1.2")) - ;; Write out the manifest entries before zipping - (org-e-odt-write-manifest-file) - ;; Save all XML files. - (mapc (lambda (file) - (let ((buf (get-file-buffer (concat org-e-odt-zip-dir file)))) - (when buf - (with-current-buffer buf - ;; Prettify output if needed. - (when org-e-odt-prettify-xml - (indent-region (point-min) (point-max))) - (save-buffer 0))))) - org-e-odt-xml-files) - ;; Run zip. - (let* ((target --out-file) - (target-name (file-name-nondirectory target)) - (target-dir (file-name-directory target)) - (cmds `(("zip" "-mX0" ,target-name "mimetype") - ("zip" "-rmTq" ,target-name ".")))) - ;; If a file with same name as the desired output file - ;; exists, remove it. - (when (file-exists-p target) - (delete-file target)) - ;; Zip up the xml files. - (let ((coding-system-for-write 'no-conversion) exitcode err-string) - (message "Creating ODT file...") - ;; Switch temporarily to content.xml. This way Zip - ;; process will inherit `org-e-odt-zip-dir' as the current - ;; directory. - (with-current-buffer - (find-file-noselect (concat org-e-odt-zip-dir "content.xml") t) - (mapc - (lambda (cmd) - (message "Running %s" (mapconcat 'identity cmd " ")) - (setq err-string - (with-output-to-string - (setq exitcode - (apply 'call-process (car cmd) - nil standard-output nil (cdr cmd))))) - (or (zerop exitcode) - (error (concat "Unable to create OpenDocument file." - (format " Zip failed with error (%s)" - err-string))))) - cmds) - ;; Zip file is now in the rightful place. - (rename-file target-name target))) - (message "Created %s" target) - ;; Cleanup work directory and work files. - (funcall --cleanup-xml-buffers) - ;; Open the OpenDocument file in archive-mode for - ;; examination. - (find-file-noselect target t) - ;; Return exported file. - (cond - ;; Case 1: Conversion desired on exported file. Run the - ;; converter on the OpenDocument file. Return the - ;; converted file. - (org-e-odt-preferred-output-format - (or (org-e-odt-convert target org-e-odt-preferred-output-format) - target)) - ;; Case 2: No further conversion. Return exported - ;; OpenDocument file. - (t target)))) - ((quit error) - ;; Cleanup work directory and work files. - (funcall --cleanup-xml-buffers) - (message "OpenDocument export failed: %s" - (error-message-string err)))))) - - - -;;;###autoload -(defun org-e-odt-export-as-odf (latex-frag &optional odf-file) - "Export LATEX-FRAG as OpenDocument formula file ODF-FILE. -Use `org-create-math-formula' to convert LATEX-FRAG first to -MathML. When invoked as an interactive command, use -`org-latex-regexps' to infer LATEX-FRAG from currently active -region. If no LaTeX fragments are found, prompt for it. Push -MathML source to kill ring, if `org-export-copy-to-kill-ring' is -non-nil." - (interactive - `(,(let (frag) - (setq frag (and (setq frag (and (region-active-p) - (buffer-substring (region-beginning) - (region-end)))) - (loop for e in org-latex-regexps - thereis (when (string-match (nth 1 e) frag) - (match-string (nth 2 e) frag))))) - (read-string "LaTeX Fragment: " frag nil frag)) - ,(let ((odf-filename (expand-file-name - (concat - (file-name-sans-extension - (or (file-name-nondirectory buffer-file-name))) - "." "odf") - (file-name-directory buffer-file-name)))) - (read-file-name "ODF filename: " nil odf-filename nil - (file-name-nondirectory odf-filename))))) - (let ((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))))) - (org-e-odt--export-wrap - filename - (let* ((buffer (progn - (require 'nxml-mode) - (let ((nxml-auto-insert-xml-declaration-flag nil)) - (find-file-noselect (concat org-e-odt-zip-dir - "content.xml") t)))) - (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) - ;; Add MathML to kill ring, if needed. - (when org-export-copy-to-kill-ring - (org-kill-new (buffer-string)))))))) - -;;;###autoload -(defun org-e-odt-export-as-odf-and-open () - "Export LaTeX fragment as OpenDocument formula and immediately open it. -Use `org-e-odt-export-as-odf' to read LaTeX fragment and OpenDocument -formula file." - (interactive) - (org-open-file (call-interactively 'org-e-odt-export-as-odf))) - -;;;###autoload -(defun org-e-odt-export-to-odt - (&optional subtreep visible-only body-only ext-plist pub-dir) - "Export current buffer to a HTML file. - -If narrowing is active in the current buffer, only export its -narrowed part. - -If a region is active, export that region. - -When optional argument SUBTREEP is non-nil, export the sub-tree -at point, extracting information from the headline properties -first. - -When optional argument VISIBLE-ONLY is non-nil, don't export -contents of hidden elements. - -When optional argument BODY-ONLY is non-nil, only write code -between \"\\begin{document}\" and \"\\end{document}\". - -EXT-PLIST, when provided, is a property list with external -parameters overriding Org default settings, but still inferior to -file-local settings. - -When optional argument PUB-DIR is set, use it as the publishing -directory. - -Return output file's name." - (interactive) - (org-e-odt--export-wrap - (org-export-output-file-name ".odt" subtreep pub-dir) - (let* ((org-e-odt-embedded-images-count 0) - (org-e-odt-embedded-formulas-count 0) - (org-e-odt-automatic-styles nil) - (org-e-odt-object-counters nil) - ;; Let `htmlfontify' know that we are interested in collecting - ;; styles. - (hfy-user-sheet-assoc nil)) - ;; Initialize content.xml and kick-off the export process. - (let ((out-buf (progn - (require 'nxml-mode) - (let ((nxml-auto-insert-xml-declaration-flag nil)) - (find-file-noselect - (concat org-e-odt-zip-dir "content.xml") t))))) - (org-export-to-buffer 'e-odt out-buf subtreep visible-only body-only))))) - - - - -(defun org-e-odt-reachable-p (in-fmt out-fmt) - "Return non-nil if IN-FMT can be converted to OUT-FMT." - (catch 'done - (let ((reachable-formats (org-e-odt-do-reachable-formats in-fmt))) - (dolist (e reachable-formats) - (let ((out-fmt-spec (assoc out-fmt (cdr e)))) - (when out-fmt-spec - (throw 'done (cons (car e) out-fmt-spec)))))))) - -(defun org-e-odt-do-convert (in-file out-fmt &optional prefix-arg) - "Workhorse routine for `org-e-odt-convert'." - (require 'browse-url) - (let* ((in-file (expand-file-name (or in-file buffer-file-name))) - (dummy (or (file-readable-p in-file) - (error "Cannot read %s" in-file))) - (in-fmt (file-name-extension in-file)) - (out-fmt (or out-fmt (error "Output format unspecified"))) - (how (or (org-e-odt-reachable-p in-fmt out-fmt) - (error "Cannot convert from %s format to %s format?" - in-fmt out-fmt))) - (convert-process (car how)) - (out-file (concat (file-name-sans-extension in-file) "." - (nth 1 (or (cdr how) out-fmt)))) - (extra-options (or (nth 2 (cdr how)) "")) - (out-dir (file-name-directory in-file)) - (cmd (format-spec convert-process - `((?i . ,(shell-quote-argument in-file)) - (?I . ,(browse-url-file-url in-file)) - (?f . ,out-fmt) - (?o . ,out-file) - (?O . ,(browse-url-file-url out-file)) - (?d . , (shell-quote-argument out-dir)) - (?D . ,(browse-url-file-url out-dir)) - (?x . ,extra-options))))) - (when (file-exists-p out-file) - (delete-file out-file)) - - (message "Executing %s" cmd) - (let ((cmd-output (shell-command-to-string cmd))) - (message "%s" cmd-output)) - - (cond - ((file-exists-p out-file) - (message "Exported to %s" out-file) - (when prefix-arg - (message "Opening %s..." out-file) - (org-open-file out-file)) - out-file) - (t - (message "Export to %s failed" out-file) - nil)))) - -(defun org-e-odt-do-reachable-formats (in-fmt) - "Return verbose info about formats to which IN-FMT can be converted. -Return a list where each element is of the -form (CONVERTER-PROCESS . OUTPUT-FMT-ALIST). See -`org-e-odt-convert-processes' for CONVERTER-PROCESS and see -`org-e-odt-convert-capabilities' for OUTPUT-FMT-ALIST." - (let* ((converter - (and org-e-odt-convert-process - (cadr (assoc-string org-e-odt-convert-process - org-e-odt-convert-processes t)))) - (capabilities - (and org-e-odt-convert-process - (cadr (assoc-string org-e-odt-convert-process - org-e-odt-convert-processes t)) - org-e-odt-convert-capabilities)) - reachable-formats) - (when converter - (dolist (c capabilities) - (when (member in-fmt (nth 1 c)) - (push (cons converter (nth 2 c)) reachable-formats)))) - reachable-formats)) - -(defun org-e-odt-reachable-formats (in-fmt) - "Return list of formats to which IN-FMT can be converted. -The list of the form (OUTPUT-FMT-1 OUTPUT-FMT-2 ...)." - (let (l) - (mapc (lambda (e) (add-to-list 'l e)) - (apply 'append (mapcar - (lambda (e) (mapcar 'car (cdr e))) - (org-e-odt-do-reachable-formats in-fmt)))) - l)) - -(defun org-e-odt-convert-read-params () - "Return IN-FILE and OUT-FMT params for `org-e-odt-do-convert'. -This is a helper routine for interactive use." - (let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read)) - (in-file (read-file-name "File to be converted: " - nil buffer-file-name t)) - (in-fmt (file-name-extension in-file)) - (out-fmt-choices (org-e-odt-reachable-formats in-fmt)) - (out-fmt - (or (and out-fmt-choices - (funcall input "Output format: " - out-fmt-choices nil nil nil)) - (error - "No known converter or no known output formats for %s files" - in-fmt)))) - (list in-file out-fmt))) - -;;;###autoload -(defun org-e-odt-convert (&optional in-file out-fmt prefix-arg) - "Convert IN-FILE to format OUT-FMT using a command line converter. -IN-FILE is the file to be converted. If unspecified, it defaults -to variable `buffer-file-name'. OUT-FMT is the desired output -format. Use `org-e-odt-convert-process' as the converter. -If PREFIX-ARG is non-nil then the newly converted file is opened -using `org-open-file'." - (interactive - (append (org-e-odt-convert-read-params) current-prefix-arg)) - (org-e-odt-do-convert in-file out-fmt prefix-arg)) - -;;; Library Initializations - -(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))) - org-e-odt-file-extensions) - -(provide 'org-e-odt) - -;;; org-e-odt.el ends here -- cgit v1.2.3