Function: org-odt-table

org-odt-table is a byte-compiled function defined in ox-odt.el.gz.

Signature

(org-odt-table TABLE CONTENTS INFO)

Documentation

Transcode a TABLE element from Org to ODT.

CONTENTS is the contents of the table. INFO is a plist holding contextual information.

Use org-odt--table to typeset the table. Handle details pertaining to indentation here.

Source Code

;; Defined in /usr/src/emacs/lisp/org/ox-odt.el.gz
(defun org-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.

Use `org-odt--table' to typeset the table.  Handle details
pertaining to indentation here."
  (let* ((--element-preceded-by-table-p
	  (lambda (element info)
	    (cl-loop for el in (org-export-get-previous-element element info t)
		     thereis (eq (org-element-type el) 'table))))
	 (--walk-list-genealogy-and-collect-tags
	  (lambda (table info)
	    (let* ((genealogy (org-element-lineage table))
		   (list-genealogy
		    (when (eq (org-element-type (car genealogy)) 'item)
		      (cl-loop for el in genealogy
			       when (memq (org-element-type el)
					  '(item plain-list))
			       collect el)))
		   (llh-genealogy
		    (apply #'nconc
			   (cl-loop
			    for el in genealogy
			    when (and (eq (org-element-type el) 'headline)
				      (org-export-low-level-p el info))
			    collect
			    (list el
				  (assq 'headline
					(org-element-contents
					 (org-export-get-parent el)))))))
		   parent-list)
	      (nconc
	       ;; Handle list genealogy.
	       (cl-loop
		for el in list-genealogy collect
		(cl-case (org-element-type el)
		  (plain-list
		   (setq parent-list el)
		   (cons "</text:list>"
			 (format "\n<text:list text:style-name=\"%s\" %s>"
				 (cl-case (org-element-property :type el)
				   (ordered "OrgNumberedList")
				   (unordered "OrgBulletedList")
				   (descriptive-1 "OrgDescriptionList")
				   (descriptive-2 "OrgDescriptionList"))
				 "text:continue-numbering=\"true\"")))
		  (item
		   (cond
		    ((not parent-list)
		     (if (funcall --element-preceded-by-table-p table info)
			 '("</text:list-header>" . "<text:list-header>")
		       '("</text:list-item>" . "<text:list-header>")))
		    ((funcall --element-preceded-by-table-p
			      parent-list info)
		     '("</text:list-header>" . "<text:list-header>"))
		    (t '("</text:list-item>" . "<text:list-item>"))))))
	       ;; Handle low-level headlines.
	       (cl-loop for el in llh-genealogy
			with step = 'item collect
			(cl-case step
			  (plain-list
			   (setq step 'item) ; Flip-flop
			   (setq parent-list el)
			   (cons "</text:list>"
				 (format "\n<text:list text:style-name=\"%s\" %s>"
					 (if (org-export-numbered-headline-p
					      el info)
					     "OrgNumberedList"
					   "OrgBulletedList")
					 "text:continue-numbering=\"true\"")))
			  (item
			   (setq step 'plain-list) ; Flip-flop
			   (cond
			    ((not parent-list)
			     (if (funcall --element-preceded-by-table-p table info)
				 '("</text:list-header>" . "<text:list-header>")
			       '("</text:list-item>" . "<text:list-header>")))
			    ((let ((section? (org-export-get-previous-element
					      parent-list info)))
			       (and section?
				    (eq (org-element-type section?) 'section)
				    (assq 'table (org-element-contents section?))))
			     '("</text:list-header>" . "<text:list-header>"))
			    (t
			     '("</text:list-item>" . "<text:list-item>"))))))))))
	 (close-open-tags (funcall --walk-list-genealogy-and-collect-tags
				   table info)))
    ;; OpenDocument schema does not permit table to occur within a
    ;; list item.

    ;; One solution - the easiest and lightweight, in terms of
    ;; implementation - is to put the table in an indented text box
    ;; and make the text box part of the list-item.  Unfortunately if
    ;; the table is big and spans multiple pages, the text box could
    ;; overflow.  In this case, the following attribute will come
    ;; handy.

    ;; ,---- From OpenDocument-v1.1.pdf
    ;; | 15.27.28 Overflow behavior
    ;; |
    ;; | For text boxes contained within text document, the
    ;; | style:overflow-behavior property specifies the behavior of text
    ;; | boxes where the containing text does not fit into the text
    ;; | box.
    ;; |
    ;; | If the attribute's value is clip, the text that does not fit
    ;; | into the text box is not displayed.
    ;; |
    ;; | If the attribute value is auto-create-new-frame, a new frame
    ;; | will be created on the next page, with the same position and
    ;; | dimensions of the original frame.
    ;; |
    ;; | If the style:overflow-behavior property's value is
    ;; | auto-create-new-frame and the text box has a minimum width or
    ;; | height specified, then the text box will grow until the page
    ;; | bounds are reached before a new frame is created.
    ;; `----

    ;; Unfortunately, LibreOffice-3.4.6 doesn't honor
    ;; auto-create-new-frame property and always resorts to clipping
    ;; the text box.  This results in table being truncated.

    ;; So we solve the problem the hard (and fun) way using list
    ;; continuations.

    ;; The problem only becomes more interesting if you take in to
    ;; account the following facts:
    ;;
    ;; - Description lists are simulated as plain lists.
    ;; - Low-level headlines can be listified.
    ;; - In Org mode, a table can occur not only as a regular list
    ;;   item, but also within description lists and low-level
    ;;   headlines.

    ;; See `org-odt--translate-description-lists' for how this is
    ;; tackled.

    (concat "\n"
	    ;; Discontinue the list.
	    (mapconcat 'car close-open-tags "\n")
	    ;; Put the table in an indented section.
	    (let* ((table (org-odt--table table contents info))
		   (level (/ (length (mapcar 'car close-open-tags)) 2))
		   (style (format "OrgIndentedSection-Level-%d" level)))
	      (when table (org-odt-format-section table style)))
	    ;; Continue the list.
	    (mapconcat 'cdr (nreverse close-open-tags) "\n"))))