Add support for indented tables in ODT export
authorJambunathan K <kjambunathan@gmail.com>
Mon, 16 Jan 2012 20:55:47 +0000 (01:55 +0530)
committerEric Schulte <eric.schulte@gmx.com>
Sun, 19 Feb 2012 15:03:39 +0000 (08:03 -0700)
* etc/styles/OrgOdtContentTemplate.xml
(OrgIndentedSection-Level-*): New section styles. These
sections are indented to the same level as the corresponding
list entries.  These sections hold tables that occur within a
list.
(OrgTable): Increased relative width from 90% to 96% for
aesthetic reasons.

* lisp/org-odt.el (org-odt-table-indentedp): New variable
(org-odt-begin-table): Modified.  If the table is within a
list, temporarily leave the list and begin an indented section
before emitting the table.
(org-odt-end-table): Modified.  If the table was within a
list, close the indented section and re-open the list
immediately after ending the table.
(org-odt-continue-list, org-odt-discontinue-list): Helper
routines to temporarily discontinue and continue a list.
(org-odt-list-stack-stashed): New variable to hold the state
of a pending list.
(org-odt-begin-list, org-odt-begin-list-item)
(org-odt-end-list-item): Modified. Handle nitty-gritties for
continuing a list and list item.
(org-odt-section-count): New variable that keeps track of
section count.  Used in conjunction with naming of sections.
(org-odt-begin-section, org-odt-end-section): New defuns.
(org-odt-init-outfile): Initialize
`org-odt-list-stack-stashed' and `org-odt-section-count'.

* lisp/org-lparse.el (org-lparse-list-item-count): Removed. Was a
superfluous variable.
(org-lparse-list-level): Removed.  Now derived from
`org-lparse-list-stack'.
(org-lparse-list-stack): New.  List that records the list
types - ordered, unordered or descriptive - in the following
order: self, parent, grand-parent etc.
(org-do-lparse): Added, removed above let-bound vars.
Disallowed regular tables within list-table block.
(org-lparse-begin-list, org-lparse-end-list)
(org-lparse-begin-list-item, org-lparse-end-list-item):
Propagate above changes.

OpenDocument doesn't permit tables to occur in the middle of a
list.  Use list continuations and indented sections to typeset
indented tables.

Fixes the following bug:
http://lists.gnu.org/archive/html/emacs-orgmode/2012-01/msg00515.html

etc/styles/OrgOdtContentTemplate.xml
lisp/org-lparse.el
lisp/org-odt.el

index f4982f6..d981631 100644 (file)
 
   <!-- automatic styles -->
   <office:automatic-styles>
+    <!-- Section styles -->
+    <style:style style:name="OrgIndentedSection-Level-1" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="1.281cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-2" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="1.905cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-3" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="2.54cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-4" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="3.175cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-5" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="3.81cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-6" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="4.445cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-7" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="5.08cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-8" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="5.715cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-9" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="6.35cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+    <style:style style:name="OrgIndentedSection-Level-10" style:family="section">
+      <style:section-properties text:dont-balance-text-columns="false" fo:margin-left="6.985cm" fo:margin-right="0cm" style:editable="false">
+       <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+      </style:section-properties>
+    </style:style>
+
+    <!-- Table styles -->
     <style:style style:name="OrgTable" style:family="table">
-      <style:table-properties style:rel-width="90%" fo:margin-top="0cm" fo:margin-bottom="0.20cm" table:align="center"/>
+      <style:table-properties style:rel-width="96%" fo:margin-top="0cm" fo:margin-bottom="0.20cm" table:align="center"/>
     </style:style>
 
     <style:style style:name="OrgTableColumn" style:family="table-column">
index 8c98ea7..4d88ba0 100644 (file)
@@ -603,11 +603,7 @@ version."
         (org-lparse-par-open-stashed 0)
 
         ;; list related vars
-        (org-lparse-list-level 0)      ; list level starts at 1. A
-                                       ; value of 0 implies we are
-                                       ; outside of any list
-        (org-lparse-list-item-count 0)
-        org-lparse-list-stack
+        (org-lparse-list-stack '())
 
         ;; list-table related vars
         org-lparse-list-table-p
@@ -1086,10 +1082,11 @@ version."
                    table-buffer (nreverse table-buffer)
                    table-orig-buffer (nreverse table-orig-buffer))
              (org-lparse-end-paragraph)
+             (when org-lparse-list-table-p
+               (error "Regular tables are not allowed in a list-table block"))
              (org-lparse-insert 'TABLE table-buffer table-orig-buffer)))
 
           ;; Normal lines
-
           (t
            ;; This line either is list item or end a list.
            (when (get-text-property 0 'list-item line)
@@ -2109,8 +2106,6 @@ When TITLE is nil, just close all open levels."
                      ("d" . description)))))
 
 ;; following vars are bound during `org-do-lparse'
-(defvar org-lparse-list-level)
-(defvar org-lparse-list-item-count)
 (defvar org-lparse-list-stack)
 (defvar org-lparse-list-table:table-row)
 (defvar org-lparse-list-table:lines)
@@ -2152,73 +2147,69 @@ When TITLE is nil, just close all open levels."
 ;; https://lists.gnu.org/archive/html/emacs-orgmode/2011-03/msg01101.html
 
 (defun org-lparse-begin-list (ltype)
-  (incf org-lparse-list-level)
-  (push org-lparse-list-item-count org-lparse-list-stack)
-  (setq org-lparse-list-item-count 0)
-  (cond
-   ((not org-lparse-list-table-p)
-    (org-lparse-begin 'LIST ltype))
-   ;; process LIST-TABLE
-   ((= 1 org-lparse-list-level)
-    ;; begin LIST-TABLE
-    (setq org-lparse-list-table:lines nil)
-    (setq org-lparse-list-table:table-row nil))
-   ((= 2 org-lparse-list-level)
-    (ignore))
-   (t
-    (org-lparse-begin 'LIST ltype))))
+  (push ltype org-lparse-list-stack)
+  (let ((list-level (length org-lparse-list-stack)))
+    (cond
+     ((not org-lparse-list-table-p)
+      (org-lparse-begin 'LIST ltype))
+     ;; process LIST-TABLE
+     ((= 1 list-level)
+      ;; begin LIST-TABLE
+      (setq org-lparse-list-table:lines nil)
+      (setq org-lparse-list-table:table-row nil))
+     ((= 2 list-level)
+      (ignore))
+     (t
+      (org-lparse-begin 'LIST ltype)))))
 
 (defun org-lparse-end-list (ltype)
-  (setq org-lparse-list-item-count (pop org-lparse-list-stack))
-  (decf org-lparse-list-level)
-  (cond
-   ((not org-lparse-list-table-p)
-    (org-lparse-end 'LIST ltype))
-   ;; process LIST-TABLE
-   ((= 0 org-lparse-list-level)
-    ;; end LIST-TABLE
-    (insert (org-lparse-format-list-table
-            (nreverse org-lparse-list-table:lines))))
-   ((= 1 org-lparse-list-level)
-    (ignore))
-   (t
-    (org-lparse-end 'LIST ltype))))
+  (pop org-lparse-list-stack)
+  (let ((list-level (length org-lparse-list-stack)))
+    (cond
+     ((not org-lparse-list-table-p)
+      (org-lparse-end 'LIST ltype))
+     ;; process LIST-TABLE
+     ((= 0 list-level)
+      ;; end LIST-TABLE
+      (insert (org-lparse-format-list-table
+              (nreverse org-lparse-list-table:lines))))
+     ((= 1 list-level)
+      (ignore))
+     (t
+      (org-lparse-end 'LIST ltype)))))
 
 (defun org-lparse-begin-list-item (ltype &optional arg headline)
-  (incf org-lparse-list-item-count)
-  (cond
-   ((not org-lparse-list-table-p)
-    (org-lparse-begin 'LIST-ITEM ltype arg headline))
-   ;; process LIST-TABLE
-   ((and (= 1 org-lparse-list-level)
-        (= 1 org-lparse-list-item-count))
-    ;; begin TABLE-ROW for LIST-TABLE
-    (setq org-lparse-list-table:table-row nil)
-    (org-lparse-begin-list-table:table-cell))
-   ((and (= 2 org-lparse-list-level)
-        (= 1 org-lparse-list-item-count))
-    ;; begin TABLE-CELL for LIST-TABLE
-    (org-lparse-begin-list-table:table-cell))
-   (t
-    (org-lparse-begin 'LIST-ITEM ltype arg headline))))
+  (let ((list-level (length org-lparse-list-stack)))
+    (cond
+     ((not org-lparse-list-table-p)
+      (org-lparse-begin 'LIST-ITEM ltype arg headline))
+     ;; process LIST-TABLE
+     ((= 1 list-level)
+      ;; begin TABLE-ROW for LIST-TABLE
+      (setq org-lparse-list-table:table-row nil)
+      (org-lparse-begin-list-table:table-cell))
+     ((= 2 list-level)
+      ;; begin TABLE-CELL for LIST-TABLE
+      (org-lparse-begin-list-table:table-cell))
+     (t
+      (org-lparse-begin 'LIST-ITEM ltype arg headline)))))
 
 (defun org-lparse-end-list-item (ltype)
-  (decf org-lparse-list-item-count)
-  (cond
-   ((not org-lparse-list-table-p)
-    (org-lparse-end 'LIST-ITEM ltype))
-   ;; process LIST-TABLE
-   ((and (= 1 org-lparse-list-level)
-        (= 0 org-lparse-list-item-count))
-    ;; end TABLE-ROW for LIST-TABLE
-    (org-lparse-end-list-table:table-cell)
-    (push (nreverse org-lparse-list-table:table-row)
-         org-lparse-list-table:lines))
-   ((= 2 org-lparse-list-level)
-    ;; end TABLE-CELL for LIST-TABLE
-    (org-lparse-end-list-table:table-cell))
-   (t
-    (org-lparse-end 'LIST-ITEM ltype))))
+  (let ((list-level (length org-lparse-list-stack)))
+    (cond
+     ((not org-lparse-list-table-p)
+      (org-lparse-end 'LIST-ITEM ltype))
+     ;; process LIST-TABLE
+     ((= 1 list-level)
+      ;; end TABLE-ROW for LIST-TABLE
+      (org-lparse-end-list-table:table-cell)
+      (push (nreverse org-lparse-list-table:table-row)
+           org-lparse-list-table:lines))
+     ((= 2 list-level)
+      ;; end TABLE-CELL for LIST-TABLE
+      (org-lparse-end-list-table:table-cell))
+     (t
+      (org-lparse-end 'LIST-ITEM ltype)))))
 
 (defvar org-lparse-list-table:table-cell-open)
 (defun org-lparse-begin-list-table:table-cell ()
index 838a327..7cff046 100644 (file)
@@ -648,6 +648,15 @@ PUB-DIR is set, use this as the publishing directory."
 (defun org-odt-end-outline-text ()
   (ignore))
 
+(defvar org-odt-section-count 0)
+(defun org-odt-begin-section (style &optional name)
+  (setq name (or name (format "Section-%d" (incf org-odt-section-count))))
+  (org-lparse-insert-tag
+   "<text:section text:style-name=\"%s\" text:name=\"%s\">" style name))
+
+(defun org-odt-end-section ()
+  (org-lparse-insert-tag "</text:section>"))
+
 (defun org-odt-begin-paragraph (&optional style)
   (org-lparse-insert-tag
    "<text:p%s>" (org-odt-get-extra-attrs-for-paragraph-style style)))
@@ -731,13 +740,17 @@ PUB-DIR is set, use this as the publishing directory."
      (list))
     (t (error "Unknown environment %s" style))))
 
-(defvar org-lparse-list-level) ; dynamically bound in org-do-lparse
+(defvar org-lparse-list-stack) ; dynamically bound in org-do-lparse
+(defvar org-odt-list-stack-stashed)
 (defun org-odt-begin-list (ltype)
   (setq ltype (or (org-lparse-html-list-type-to-canonical-list-type ltype)
                  ltype))
   (let* ((style-name (org-odt-get-style-name-for-entity 'list ltype))
-        (extra (concat (when (= org-lparse-list-level 1)
-                         " text:continue-numbering=\"false\"")
+        (extra (concat (if (or org-lparse-list-table-p
+                               (and (= 1 (length org-lparse-list-stack))
+                                    (null org-odt-list-stack-stashed)))
+                           " text:continue-numbering=\"false\""
+                         " text:continue-numbering=\"true\"")
                        (when style-name
                          (format " text:style-name=\"%s\""  style-name)))))
     (case ltype
@@ -760,11 +773,15 @@ PUB-DIR is set, use this as the publishing directory."
     (ordered
      (assert (not headline) t)
      (let* ((counter arg) (extra ""))
-       (org-lparse-insert-tag "<text:list-item>")
+       (org-lparse-insert-tag (if (= (length org-lparse-list-stack)
+                                    (length org-odt-list-stack-stashed))
+                                 "<text:list-header>" "<text:list-item>"))
        (org-lparse-begin-paragraph)))
     (unordered
      (let* ((id arg) (extra ""))
-       (org-lparse-insert-tag "<text:list-item>")
+       (org-lparse-insert-tag (if (= (length org-lparse-list-stack)
+                                    (length org-odt-list-stack-stashed))
+                                 "<text:list-header>" "<text:list-item>"))
        (org-lparse-begin-paragraph)
        (insert (if headline (org-odt-format-target headline id)
                 (org-odt-format-bookmark "" id)))))
@@ -785,13 +802,30 @@ PUB-DIR is set, use this as the publishing directory."
                  ltype))
   (case ltype
     ((ordered unordered)
-     (org-lparse-insert-tag "</text:list-item>"))
+     (org-lparse-insert-tag (if (= (length org-lparse-list-stack)
+                                  (length org-odt-list-stack-stashed))
+                               (prog1 "</text:list-header>"
+                                 (setq org-odt-list-stack-stashed nil))
+                             "</text:list-item>")))
     (description
      (org-lparse-end-list-item-1)
      (org-lparse-end-list 'description)
      (org-lparse-end-list-item-1))
     (t (error "Unknown list type"))))
 
+(defun org-odt-discontinue-list ()
+  (let ((stashed-stack org-lparse-list-stack))
+    (loop for list-type in stashed-stack
+         do (org-lparse-end-list-item-1 list-type)
+         (org-lparse-end-list list-type))
+    (setq org-odt-list-stack-stashed stashed-stack)))
+
+(defun org-odt-continue-list ()
+  (setq org-odt-list-stack-stashed (nreverse org-odt-list-stack-stashed))
+  (loop for list-type in org-odt-list-stack-stashed
+       do (org-lparse-begin-list list-type)
+       (org-lparse-begin-list-item list-type)))
+
 ;; Following variables are let bound when table emission is in
 ;; progress. See org-lparse.el.
 (defvar org-lparse-table-begin-marker)
@@ -899,7 +933,19 @@ style from the list."
                               :key-type symbol
                               :value-type (const :tag "True" t))))))
 
+(defvar org-odt-table-indentedp nil)
 (defun org-odt-begin-table (caption label attributes)
+  (setq org-odt-table-indentedp (not (null org-lparse-list-stack)))
+  (when org-odt-table-indentedp
+    ;; Within the Org file, the table is appearing within a list item.
+    ;; OpenDocument doesn't allow table to appear within list items.
+    ;; Temporarily terminate the list, emit the table and then
+    ;; re-continue the list.
+    (org-odt-discontinue-list)
+    ;; Put the Table in an indented section.
+    (let ((level (length org-odt-list-stack-stashed)))
+      (org-odt-begin-section (format "OrgIndentedSection-Level-%d" level))))
+
   (setq org-odt-table-style attributes)
   (setq org-odt-table-style-spec
        (assoc org-odt-table-style org-export-odt-table-styles))
@@ -942,7 +988,10 @@ style from the list."
         ((equal spec "table-cell:style-name")
          (replace-match table-cell-style t t))))))
   (goto-char (point-max))
-  (org-lparse-insert-tag "</table:table>"))
+  (org-lparse-insert-tag "</table:table>")
+  (when org-odt-table-indentedp
+    (org-odt-end-section)
+    (org-odt-continue-list)))
 
 (defun org-odt-begin-table-rowgroup (&optional is-header-row)
   (when org-lparse-table-rowgrp-open
@@ -2055,7 +2104,9 @@ CATEGORY-HANDLE is used.  See
     (setq org-odt-manifest-file-entries nil
          org-odt-embedded-images-count 0
          org-odt-embedded-formulas-count 0
+         org-odt-section-count 0
          org-odt-entity-labels-alist nil
+         org-odt-list-stack-stashed nil
          org-odt-entity-counts-plist nil)
     content-file))