Browse Source

Merge branch 'master' of orgmode.org:org-mode

Carsten Dominik 14 years ago
parent
commit
a7d89a80fb

+ 1 - 1
contrib/babel/langs/ob-fortran.el

@@ -139,7 +139,7 @@ of the same value."
       (format "integer, parameter  ::  %S = %S\n" var val))
       (format "integer, parameter  ::  %S = %S\n" var val))
      ((floatp val)
      ((floatp val)
       (format "real, parameter ::  %S = %S\n" var val))
       (format "real, parameter ::  %S = %S\n" var val))
-     ((or (characterp val))
+     ((or (integerp val))
       (format "character, parameter :: %S = '%S'\n" var val))
       (format "character, parameter :: %S = '%S'\n" var val))
      ((stringp val)
      ((stringp val)
       (format "character(len=%d), parameter ::  %S = '%s'\n"
       (format "character(len=%d), parameter ::  %S = '%s'\n"

+ 355 - 145
contrib/lisp/org-odt.el

@@ -31,6 +31,8 @@
 (require 'org-lparse)
 (require 'org-lparse)
 
 
 (defun org-odt-end-export ()
 (defun org-odt-end-export ()
+  (org-odt-fixup-label-references)
+
   ;; remove empty paragraphs
   ;; remove empty paragraphs
   (goto-char (point-min))
   (goto-char (point-min))
   (while (re-search-forward
   (while (re-search-forward
@@ -598,15 +600,107 @@ PUB-DIR is set, use this as the publishing directory."
 (defvar org-lparse-table-is-styled)
 (defvar org-lparse-table-is-styled)
 (defvar org-lparse-table-rowgrp-info)
 (defvar org-lparse-table-rowgrp-info)
 (defvar org-lparse-table-colalign-vector)
 (defvar org-lparse-table-colalign-vector)
+
+(defvar org-odt-table-style nil
+  "Table style specified by \"#+ATTR_ODT: <style-name>\" line.
+This is set during `org-odt-begin-table'.")
+
+(defvar org-odt-table-style-spec nil
+  "Entry for `org-odt-table-style' in `org-export-odt-table-styles'.")
+
+(defcustom org-export-odt-table-styles nil
+  "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
+`org-odt-table-style'.
+
+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-export-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-export-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
+\"<table:table-template>\" elements contained within
+\"<office:styles>\".  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 \"<table:table>\" element.  Refer ODF-1.2
+specification for more information.  Also consult the
+implementation filed under `org-odt-get-table-cell-styles'."
+  :group 'org-export-odt
+  :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))))))
+
 (defun org-odt-begin-table (caption label attributes)
 (defun org-odt-begin-table (caption label attributes)
+  (setq org-odt-table-style attributes)
+  (setq org-odt-table-style-spec
+	(assoc org-odt-table-style org-export-odt-table-styles))
   (when label
   (when label
     (insert
     (insert
      (org-odt-format-stylized-paragraph
      (org-odt-format-stylized-paragraph
       'table (org-odt-format-entity-caption label caption "Table"))))
       'table (org-odt-format-entity-caption label caption "Table"))))
-
   (org-lparse-insert-tag
   (org-lparse-insert-tag
    "<table:table table:name=\"%s\" table:style-name=\"%s\">"
    "<table:table table:name=\"%s\" table:style-name=\"%s\">"
-   (or label "") "OrgTable")
+   (or label "") (or (nth 1 org-odt-table-style-spec) "OrgTable"))
   (setq org-lparse-table-begin-marker (point)))
   (setq org-lparse-table-begin-marker (point)))
 
 
 (defun org-odt-end-table ()
 (defun org-odt-end-table ()
@@ -614,22 +708,24 @@ PUB-DIR is set, use this as the publishing directory."
   (loop for level from 0 below org-lparse-table-ncols
   (loop for level from 0 below org-lparse-table-ncols
 	do (insert
 	do (insert
 	    (org-odt-format-tags
 	    (org-odt-format-tags
-	     "<table:table-column table:style-name=\"OrgTableColumn\"/>"  "")))
+	     "<table:table-column table:style-name=\"%sColumn\"/>"
+	     "" (or (nth 1 org-odt-table-style-spec) "OrgTable"))))
 
 
   ;; fill style attributes for table cells
   ;; fill style attributes for table cells
   (when org-lparse-table-is-styled
   (when org-lparse-table-is-styled
     (while (re-search-forward "@@\\(table-cell:p\\|table-cell:style-name\\)@@\\([0-9]+\\)@@\\([0-9]+\\)@@" nil t)
     (while (re-search-forward "@@\\(table-cell:p\\|table-cell:style-name\\)@@\\([0-9]+\\)@@\\([0-9]+\\)@@" nil t)
-      (let ((spec (match-string 1))
-	    (r (string-to-number (match-string 2)))
-	    (c (string-to-number (match-string 3))))
+      (let* ((spec (match-string 1))
+	     (r (string-to-number (match-string 2)))
+	     (c (string-to-number (match-string 3)))
+	     (cell-styles (org-odt-get-table-cell-styles
+			   r c org-odt-table-style-spec))
+	     (table-cell-style (car cell-styles))
+	     (table-cell-paragraph-style (cdr cell-styles)))
 	(cond
 	(cond
 	 ((equal spec "table-cell:p")
 	 ((equal spec "table-cell:p")
-	  (let ((style-name (org-odt-get-paragraph-style-for-table-cell r c)))
-	    (replace-match style-name t t)))
+	  (replace-match table-cell-paragraph-style t t))
 	 ((equal spec "table-cell:style-name")
 	 ((equal spec "table-cell:style-name")
-	  (let ((style-name (org-odt-get-style-name-for-table-cell r c)))
-	    (replace-match style-name t t)))))))
-
+	  (replace-match table-cell-style t t))))))
   (goto-char (point-max))
   (goto-char (point-max))
   (org-lparse-insert-tag "</table:table>"))
   (org-lparse-insert-tag "</table:table>"))
 
 
@@ -653,30 +749,87 @@ PUB-DIR is set, use this as the publishing directory."
   (org-odt-format-tags
   (org-odt-format-tags
    '("<table:table-row>" . "</table:table-row>") row))
    '("<table:table-row>" . "</table:table-row>") row))
 
 
-(defun org-odt-get-style-name-for-table-cell (r c)
-  (concat
-   "OrgTblCell"
-   (cond
-    ((= r 0) "T")
-    ((eq (cdr (assoc r org-lparse-table-rowgrp-info))  :start) "T")
-    (t ""))
-   (when (= r org-lparse-table-rownum) "B")
-   (cond
-    ((= c 0) "")
-    ((or (memq (nth c org-table-colgroup-info) '(:start :startend))
-	 (memq (nth (1- c) org-table-colgroup-info) '(:end :startend))) "L")
-    (t ""))))
-
-(defun org-odt-get-paragraph-style-for-table-cell (r c)
-  (capitalize (aref org-lparse-table-colalign-vector c)))
+(defun org-odt-get-table-cell-styles (r c &optional style-spec)
+  "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-export-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-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."
+  (cond
+   (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))
+		   (= c (1- org-lparse-table-ncols))) "LastColumn")
+	     ((and (cdr (assoc 'use-first-row-styles cell-style-selectors))
+		   (= r 0)) "FirstRow")
+	     ((and (cdr (assoc 'use-last-row-styles cell-style-selectors))
+		   (= r org-lparse-table-rownum))
+	      "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 ""))))
+      (cons
+       (concat template-name cell-type "TableCell")
+       (concat template-name cell-type "TableParagraph"))))
+   (t
+    (cons
+     (concat
+      "OrgTblCell"
+      (cond
+       ((= r 0) "T")
+       ((eq (cdr (assoc r org-lparse-table-rowgrp-info))  :start) "T")
+       (t ""))
+      (when (= r org-lparse-table-rownum) "B")
+      (cond
+       ((= c 0) "")
+       ((or (memq (nth c org-table-colgroup-info) '(:start :startend))
+	    (memq (nth (1- c) org-table-colgroup-info) '(:end :startend))) "L")
+       (t "")))
+     (capitalize (aref org-lparse-table-colalign-vector c))))))
 
 
 (defun org-odt-get-paragraph-style-cookie-for-table-cell (r c)
 (defun org-odt-get-paragraph-style-cookie-for-table-cell (r c)
   (concat
   (concat
-   (cond
-    (org-lparse-table-cur-rowgrp-is-hdr "OrgTableHeading")
-    ((and (= c 0) (org-lparse-get 'TABLE-FIRST-COLUMN-AS-LABELS))
-     "OrgTableHeading")
-    (t "OrgTableContents"))
+   (and (not org-odt-table-style-spec)
+	(cond
+	 (org-lparse-table-cur-rowgrp-is-hdr "OrgTableHeading")
+	 ((and (= c 0) (org-lparse-get 'TABLE-FIRST-COLUMN-AS-LABELS))
+	  "OrgTableHeading")
+	 (t "OrgTableContents")))
    (and org-lparse-table-is-styled
    (and org-lparse-table-is-styled
 	(format "@@table-cell:p@@%03d@@%03d@@" r c))))
 	(format "@@table-cell:p@@%03d@@%03d@@" r c))))
 
 
@@ -1017,51 +1170,11 @@ value of `org-export-odt-use-htmlfontify."
 	       (org-odt-copy-image-file thefile) thelink))))
 	       (org-odt-copy-image-file thefile) thelink))))
     (org-export-odt-format-image thefile href)))
     (org-export-odt-format-image thefile href)))
 
 
-(defun org-export-odt-do-format-numbered-formula (embed-as caption attr label
-							   width height href)
-  (with-temp-buffer
-    (let ((org-lparse-table-colalign-info '((0 "c" "8") (0 "c" "1"))))
-      (org-lparse-insert-list-table
-       `((,(org-export-odt-do-format-formula ; caption and label
-					     ; should be nil
-	    embed-as nil attr nil width height href)
-	  ,(org-odt-format-entity-caption label caption "Equation")))
-       nil nil nil nil nil org-lparse-table-colalign-info))
-    (buffer-substring-no-properties (point-min) (point-max))))
-
-(defun org-export-odt-do-format-formula (embed-as caption attr label
-						  width height href)
-  "Create image tag with source and attributes."
-  (save-match-data
-    (cond
-     ((and (not caption) (not label))
-      (let (style-name anchor-type)
-	(case embed-as
-	  (paragraph
-	   (setq style-name  "OrgSimpleGraphics" anchor-type "paragraph"))
-	  (character
-	   (setq style-name  "OrgInlineGraphics" anchor-type "as-char"))
-	  (t
-	   (error "Unknown value for embed-as %S" embed-as)))
-	(org-odt-format-frame href style-name width height nil anchor-type)))
-     (t
-      (concat
-       (org-odt-format-textbox
-	(org-odt-format-stylized-paragraph
-	 'illustration
-	 (concat
-	  (let ((extra ""))
-	    (org-odt-format-frame
-	     href "" width height extra "paragraph"))
-	  (org-odt-format-entity-caption label caption)))
-	"OrgCaptionFrame" width height))))))
-
 (defun org-export-odt-format-formula (src href &optional embed-as)
 (defun org-export-odt-format-formula (src href &optional embed-as)
   "Create image tag with source and attributes."
   "Create image tag with source and attributes."
   (save-match-data
   (save-match-data
     (let* ((caption (org-find-text-property-in-string 'org-caption src))
     (let* ((caption (org-find-text-property-in-string 'org-caption src))
 	   (caption (and caption (org-xml-format-desc caption)))
 	   (caption (and caption (org-xml-format-desc caption)))
-	   (attr (org-find-text-property-in-string 'org-attributes src))
 	   (label (org-find-text-property-in-string 'org-label src))
 	   (label (org-find-text-property-in-string 'org-label src))
 	   (embed-as (or embed-as
 	   (embed-as (or embed-as
 			 (and (org-find-text-property-in-string
 			 (and (org-find-text-property-in-string
@@ -1069,11 +1182,20 @@ value of `org-export-odt-use-htmlfontify."
 			      (org-find-text-property-in-string
 			      (org-find-text-property-in-string
 			       'org-latex-src-embed-type src))
 			       'org-latex-src-embed-type src))
 			 'paragraph))
 			 'paragraph))
-	   (attr-plist (when attr (read  attr)))
-	   (width (plist-get attr-plist :width))
-	   (height (plist-get attr-plist :height)))
-      (org-export-odt-do-format-formula
-       embed-as caption attr label width height href))))
+	   width height)
+      (cond
+       ((eq embed-as 'character)
+	(org-odt-format-entity "InlineFormula" href width height))
+       (t
+	(org-lparse-end-paragraph)
+	(org-lparse-insert-list-table
+	 `((,(org-odt-format-entity
+	      (if caption "CaptionedDisplayFormula" "DisplayFormula")
+	      href width height caption nil)
+	    ,(if (not label) ""
+	       (org-odt-format-entity-caption label nil "Equation"))))
+	 nil nil nil "OrgEquation" nil '((1 "c" 8) (2 "c" 1)))
+	(throw 'nextline nil))))))
 
 
 (defvar org-odt-embedded-formulas-count 0)
 (defvar org-odt-embedded-formulas-count 0)
 (defun org-odt-copy-formula-file (path)
 (defun org-odt-copy-formula-file (path)
@@ -1256,12 +1378,20 @@ MAY-INLINE-P allows inlining it as an image."
 	   (size (org-odt-image-size-from-file
 	   (size (org-odt-image-size-from-file
 		  src (plist-get attr-plist :width)
 		  src (plist-get attr-plist :width)
 		  (plist-get attr-plist :height)
 		  (plist-get attr-plist :height)
-		  (plist-get attr-plist :scale) nil embed-as)))
-      (org-export-odt-do-format-image
-       embed-as caption attr label (car size) (cdr size) href))))
+		  (plist-get attr-plist :scale) nil embed-as))
+	   (width (car size)) (height (cdr size)))
+      (cond
+       ((not (or caption label))
+	(case embed-as
+	  (paragraph (org-odt-format-entity "DisplayImage" href width height))
+	  (character (org-odt-format-entity "InlineImage" href width height))
+	  (t (error "Unknown value for embed-as %S" embed-as))))
+       (t
+	(org-odt-format-entity
+	 "CaptionedDisplayImage" href width height caption label))))))
 
 
-(defun org-odt-format-frame (text style &optional
-				  width height extra anchor-type)
+(defun org-odt-format-frame (text width height style &optional
+				  extra anchor-type)
   (let ((frame-attrs
   (let ((frame-attrs
 	 (concat
 	 (concat
 	  (if width (format " svg:width=\"%0.2fcm\"" width) "")
 	  (if width (format " svg:width=\"%0.2fcm\"" width) "")
@@ -1272,13 +1402,14 @@ MAY-INLINE-P allows inlining it as an image."
      '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
      '("<draw:frame draw:style-name=\"%s\"%s>" . "</draw:frame>")
      text style frame-attrs)))
      text style frame-attrs)))
 
 
-(defun org-odt-format-textbox (text style &optional width height extra)
+(defun org-odt-format-textbox (text width height style &optional
+				    extra anchor-type)
   (org-odt-format-frame
   (org-odt-format-frame
    (org-odt-format-tags
    (org-odt-format-tags
     '("<draw:text-box %s>" . "</draw:text-box>")
     '("<draw:text-box %s>" . "</draw:text-box>")
     text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
     text (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
 		 (format " fo:min-width=\"%0.2fcm\"" (or width .2))))
 		 (format " fo:min-width=\"%0.2fcm\"" (or width .2))))
-   style width nil extra))
+   width nil style extra anchor-type))
 
 
 (defun org-odt-format-inlinetask (heading content
 (defun org-odt-format-inlinetask (heading content
 					  &optional todo priority tags)
 					  &optional todo priority tags)
@@ -1289,33 +1420,34 @@ MAY-INLINE-P allows inlining it as an image."
 		 (org-lparse-format
 		 (org-lparse-format
 		  'HEADLINE (concat (org-lparse-format-todo todo) " " heading)
 		  'HEADLINE (concat (org-lparse-format-todo todo) " " heading)
 		  nil tags))
 		  nil tags))
-		content) "OrgInlineTaskFrame" nil nil " style:rel-width=\"100%\"")))
-(defun org-export-odt-do-format-image (embed-as caption attr label
-						width height href)
-  "Create image tag with source and attributes."
-  (save-match-data
-    (cond
-     ((and (not caption) (not label))
-      (let (style-name anchor-type)
-	(case embed-as
-	  (paragraph
-	   (setq style-name  "OrgSimpleGraphics" anchor-type "paragraph"))
-	  (character
-	   (setq style-name  "OrgInlineGraphics" anchor-type "as-char"))
-	  (t
-	   (error "Unknown value for embed-as %S" embed-as)))
-	(org-odt-format-frame href style-name width height nil anchor-type)))
-     (t
-      (concat
-       (org-odt-format-textbox
-	(org-odt-format-stylized-paragraph
-	 'illustration
-	 (concat
-	  (let ((extra " style:rel-width=\"100%\" style:rel-height=\"scale\""))
-	    (org-odt-format-frame
-	     href "OrgCaptionedGraphics" width height extra "paragraph"))
-	  (org-odt-format-entity-caption label caption)))
-	"OrgCaptionFrame" width height))))))
+		content) nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\"")))
+
+(defvar org-odt-entity-frame-styles
+  '(("InlineImage" "Figure" ("OrgInlineImage" nil "as-char"))
+    ("DisplayImage" "Figure" ("OrgDisplayImage" nil "paragraph"))
+    ("CaptionedDisplayImage" "Figure"
+     ("OrgCaptionedImage"
+      " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
+     ("OrgImageCaptionFrame"))
+    ("InlineFormula" "Equation" ("OrgInlineFormula" nil "as-char"))
+    ("DisplayFormula" "Equation" ("OrgDisplayFormula" nil "as-char"))
+    ("CaptionedDisplayFormula" "Equation"
+     ("OrgCaptionedFormula" nil "paragraph")
+     ("OrgFormulaCaptionFrame" nil "as-char"))))
+
+(defun org-odt-format-entity (entity href width height &optional caption label)
+  (let* ((entity-style (assoc entity org-odt-entity-frame-styles))
+	 (entity-frame (apply 'org-odt-format-frame
+			      href width height (nth 2 entity-style))))
+    (if (not (or caption label)) entity-frame
+      (apply 'org-odt-format-textbox
+	     (org-odt-format-stylized-paragraph
+	      'illustration
+	      (concat entity-frame (org-odt-format-entity-caption
+				    label caption (nth 1 entity-style))))
+	     width height (nth 3 entity-style)))))
+
+
 
 
 (defvar org-odt-embedded-images-count 0)
 (defvar org-odt-embedded-images-count 0)
 (defun org-odt-copy-image-file (path)
 (defun org-odt-copy-image-file (path)
@@ -1401,22 +1533,105 @@ MAY-INLINE-P allows inlining it as an image."
      (t (ignore)))
      (t (ignore)))
     (cons width height)))
     (cons width height)))
 
 
-(defvar org-odt-default-entity "Illustration")
-(defun org-odt-format-entity-caption (label caption &optional default-entity)
-  (if (not label) (or caption "")
-    (let* ((label-components (org-odt-parse-label label))
-	   (entity (car label-components))
-	   (seqno (cdr label-components))
-	   (caption (and caption (concat ": " caption))))
-      (unless seqno
-	(setq seqno label
-	      entity (or default-entity org-odt-default-entity)))
-      (concat
-       entity " "
-       (org-odt-format-tags
-	'("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
-	seqno label entity entity)
-       caption))))
+(defvar org-odt-entity-labels-alist nil
+  "Associate Labels with the Labelled entities.
+Each element of the alist is of the form (LABEL-NAME
+CATEGORY-NAME SEQNO).  LABEL-NAME is same as that specified by
+\"#+LABEL: ...\" line.  CATEGORY-NAME is the type of the entity
+that LABEL-NAME is attached to.  CATEGORY-NAME can be one of
+\"Table\", \"Figure\" or \"Equation\".  SEQNO is the unique
+number assigned to the referenced entity on a per-CATEGORY basis.
+It is generated sequentially and is 1-based.
+
+Update this alist with `org-odt-add-label-definition' and
+retrieve an entry with `org-odt-get-label-definition'.")
+
+(defvar org-odt-entity-counts-plist nil
+  "Plist of running counters of SEQNOs for each of the CATEGORY-NAMEs.
+See `org-odt-entity-labels-alist' for known CATEGORY-NAMEs.")
+
+(defvar org-odt-label-def-ref-spec
+  '(("Equation" "(%n)" "text" "(%n)")
+    ("" "%e %n%c" "category-and-value" "%e %n"))
+  "Specify how labels are applied and referenced.
+This is an alist where each element is of the form (CATEGORY-NAME
+LABEL-APPLY-FMT LABEL-REF-MODE LABEL-REF-FMT).  CATEGORY-NAME is
+as defined in `org-odt-entity-labels-alist'.  It can additionally
+be an empty string in which case it is used as a catch-all
+specifier.
+
+LABEL-APPLY-FMT is used for applying labels and captions.  It may
+contain following specifiers - %e, %n and %c.  %e is replaced
+with the CATEGORY-NAME.  %n is replaced with \"<text:sequence
+...> SEQNO </text:sequence>\".  %c is replaced with CAPTION. See
+`org-odt-format-label-definition'.
+
+LABEL-REF-MODE and LABEL-REF-FMT are used for generating the
+following label reference - \"<text:sequence-ref
+text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
+</text:sequence-ref>\".  LABEL-REF-FMT may contain following
+specifiers - %e and %n.  %e is replaced with the CATEGORY-NAME.  %n is
+replaced with SEQNO. See `org-odt-format-label-reference'.")
+
+(defun org-odt-add-label-definition (label category)
+  "Return (SEQNO . LABEL-APPLY-FMT).
+See `org-odt-label-def-ref-spec'."
+  (setq label (substring-no-properties label))
+  (let (seqno label-props fmt (category-sym (intern category)))
+    (setq seqno (1+ (plist-get org-odt-entity-counts-plist category-sym))
+	  org-odt-entity-counts-plist (plist-put org-odt-entity-counts-plist
+						 category-sym seqno)
+	  fmt (cadr (or (assoc-string category org-odt-label-def-ref-spec t)
+			(assoc-string "" org-odt-label-def-ref-spec t)))
+	  label-props (list label category seqno))
+    (push label-props org-odt-entity-labels-alist)
+    (cons seqno fmt)))
+
+(defun org-odt-get-label-definition (label)
+  "Return (LABEL-NAME CATEGORY-NAME SEQNO LABEL-REF-MODE LABEL-REF-FMT).
+See `org-odt-entity-labels-alist' and
+`org-odt-label-def-ref-spec'."
+  (let* ((label-props (assoc label org-odt-entity-labels-alist))
+	 (category (nth 1 label-props)))
+    (append label-props
+	    (cddr (or (assoc-string category org-odt-label-def-ref-spec t)
+		      (assoc-string "" org-odt-label-def-ref-spec t))))))
+
+(defun org-odt-format-label-definition (label category caption)
+  (assert label)
+  (let* ((label-props (org-odt-add-label-definition label category))
+	 (seqno (car label-props))
+	 (fmt (cdr label-props)))
+    (or (format-spec
+	 fmt
+	 `((?e . ,category)
+	   (?n . ,(org-odt-format-tags
+		   '("<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">" . "</text:sequence>")
+		   (format "%d" seqno) label category category))
+	   (?c . ,(or (and caption (concat ": " caption)) ""))))
+	caption "")))
+
+(defun org-odt-format-label-reference (label category seqno fmt1 fmt2)
+  (assert label)
+  (save-match-data
+    (org-odt-format-tags
+     '("<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">"
+       . "</text:sequence-ref>")
+     (format-spec fmt2 `((?e . ,category)
+			 (?n . ,(format "%d" seqno)))) fmt1 label)))
+
+(defun org-odt-fixup-label-references ()
+  (goto-char (point-min))
+  (while (re-search-forward
+	  "<text:sequence-ref text:ref-name=\"\\([^\"]+\\)\"/>" nil t)
+    (let* ((label (match-string 1)))
+      (replace-match
+       (apply 'org-odt-format-label-reference
+	      (org-odt-get-label-definition label)) t t))))
+
+(defun org-odt-format-entity-caption (label caption category)
+  (or (and label (org-odt-format-label-definition label category caption))
+      caption ""))
 
 
 (defun org-odt-format-tags (tag text &rest args)
 (defun org-odt-format-tags (tag text &rest args)
   (let ((prefix (when org-lparse-encode-pending "@"))
   (let ((prefix (when org-lparse-encode-pending "@"))
@@ -1437,8 +1652,9 @@ MAY-INLINE-P allows inlining it as an image."
     ;; reset variables
     ;; reset variables
     (setq org-odt-manifest-file-entries nil
     (setq org-odt-manifest-file-entries nil
 	  org-odt-embedded-images-count 0
 	  org-odt-embedded-images-count 0
-	  org-odt-embedded-formulas-count 0)
-
+	  org-odt-embedded-formulas-count 0
+	  org-odt-entity-labels-alist nil
+	  org-odt-entity-counts-plist (list 'Table 0 'Equation 0 'Figure 0))
     content-file))
     content-file))
 
 
 (defcustom org-export-odt-prettify-xml nil
 (defcustom org-export-odt-prettify-xml nil
@@ -1673,14 +1889,6 @@ visually."
     (CODING-SYSTEM-FOR-SAVE 'utf-8)
     (CODING-SYSTEM-FOR-SAVE 'utf-8)
     (t (error "Unknown property: %s"  what))))
     (t (error "Unknown property: %s"  what))))
 
 
-(defun org-odt-parse-label (label)
-  (save-match-data
-    (if (not (string-match "\\`[a-zA-Z]+:\\(.+\\)" label))
-	(cons label nil)
-      (cons
-       (capitalize (substring label 0 (1- (match-beginning 1))))
-       (substring label (match-beginning 1))))))
-
 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
 (defvar org-lparse-opt-plist)		    ; bound during org-do-lparse
 (defvar org-lparse-opt-plist)		    ; bound during org-do-lparse
 (defun org-export-odt-do-preprocess-latex-fragments ()
 (defun org-export-odt-do-preprocess-latex-fragments ()
@@ -1722,16 +1930,18 @@ visually."
   (let (label label-components category value pretty-label)
   (let (label label-components category value pretty-label)
     (while (re-search-forward "\\\\ref{\\([^{}\n]+\\)}" nil t)
     (while (re-search-forward "\\\\ref{\\([^{}\n]+\\)}" nil t)
       (org-if-unprotected-at (match-beginning 1)
       (org-if-unprotected-at (match-beginning 1)
-	(setq label (match-string 1)
-	      label-components (org-odt-parse-label label)
-	      category (car label-components)
-	      value (cdr label-components)
-	      pretty-label (if value (concat category " " value) label))
 	(replace-match
 	(replace-match
-	 (let ((org-lparse-encode-pending t))
+	 (let ((org-lparse-encode-pending t)
+	       (label (match-string 1)))
+	   ;; markup generated below is mostly an eye-candy.  At
+	   ;; pre-processing stage, there is no information on which
+	   ;; entity a label reference points to.  The actual markup
+	   ;; is generated as part of `org-odt-fixup-label-references'
+	   ;; which gets called at the fag end of export.  By this
+	   ;; time we would have seen and collected all the label
+	   ;; definitions in `org-odt-entity-labels-alist'.
 	   (org-odt-format-tags
 	   (org-odt-format-tags
-	    '("<text:sequence-ref text:reference-format=\"category-and-value\" text:ref-name=\"%s\">"
-	      . "</text:sequence-ref>") pretty-label label)) t t)))))
+	    "<text:sequence-ref text:ref-name=\"%s\"/>" "" label)) t t)))))
 
 
 ;; process latex fragments as part of
 ;; process latex fragments as part of
 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook
 ;; `org-export-preprocess-after-blockquote-hook'. Note that this hook

+ 39 - 17
contrib/odt/styles/OrgOdtContentTemplate.xml

@@ -46,7 +46,7 @@
   <!-- automatic styles -->
   <!-- automatic styles -->
   <office:automatic-styles>
   <office:automatic-styles>
     <style:style style:name="OrgTable" style:family="table">
     <style:style style:name="OrgTable" style:family="table">
-      <style:table-properties style:rel-width="90%" table:align="center"/>
+      <style:table-properties style:rel-width="90%" fo:margin-top="0cm" fo:margin-bottom="0.20cm" table:align="center"/>
     </style:style>
     </style:style>
 
 
     <style:style style:name="OrgTableColumn" style:family="table-column">
     <style:style style:name="OrgTableColumn" style:family="table-column">
@@ -57,50 +57,72 @@
       <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
       <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellL" style:family="table-cell">
     <style:style style:name="OrgTblCellL" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="0.035cm solid #808080" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="0.002cm solid #000000" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellR" style:family="table-cell">
     <style:style style:name="OrgTblCellR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellLR" style:family="table-cell">
     <style:style style:name="OrgTblCellLR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="0.035cm solid #808080" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellT" style:family="table-cell">
     <style:style style:name="OrgTblCellT" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTL" style:family="table-cell">
     <style:style style:name="OrgTblCellTL" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="none" fo:border-left="0.035cm solid #808080" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="none" fo:border-left="0.002cm solid #000000" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTR" style:family="table-cell">
     <style:style style:name="OrgTblCellTR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="none" fo:border-left="none" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="none" fo:border-left="none" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTLR" style:family="table-cell">
     <style:style style:name="OrgTblCellTLR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="none" fo:border-left="0.035cm solid #808080" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="none" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellB" style:family="table-cell">
     <style:style style:name="OrgTblCellB" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.035cm solid #808080" fo:border-left="none" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.002cm solid #000000" fo:border-left="none" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellBL" style:family="table-cell">
     <style:style style:name="OrgTblCellBL" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.035cm solid #808080" fo:border-left="0.035cm solid #808080" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.002cm solid #000000" fo:border-left="0.002cm solid #000000" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellBR" style:family="table-cell">
     <style:style style:name="OrgTblCellBR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.035cm solid #808080" fo:border-left="none" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.002cm solid #000000" fo:border-left="none" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellBLR" style:family="table-cell">
     <style:style style:name="OrgTblCellBLR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.035cm solid #808080" fo:border-left="0.035cm solid #808080" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="0.002cm solid #000000" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTB" style:family="table-cell">
     <style:style style:name="OrgTblCellTB" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="0.035cm solid #808080" fo:border-left="none" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000" fo:border-left="none" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTBL" style:family="table-cell">
     <style:style style:name="OrgTblCellTBL" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="0.035cm solid #808080" fo:border-left="0.035cm solid #808080" fo:border-right="none"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000" fo:border-left="0.002cm solid #000000" fo:border-right="none"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTBR" style:family="table-cell">
     <style:style style:name="OrgTblCellTBR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="0.035cm solid #808080" fo:border-left="none" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000" fo:border-left="none" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
     <style:style style:name="OrgTblCellTBLR" style:family="table-cell">
     <style:style style:name="OrgTblCellTBLR" style:family="table-cell">
-      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.035cm solid #808080" fo:border-bottom="0.035cm solid #808080" fo:border-left="0.035cm solid #808080" fo:border-right="0.035cm solid #808080"/>
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000"/>
     </style:style>
     </style:style>
+
+    <!-- BEGIN: Table styles for numbered equations -->
+    <style:style style:name="OrgEquation" style:family="table">
+      <style:table-properties style:rel-width="100%" fo:margin-top="0cm" fo:margin-bottom="0.20cm" table:align="center"/>
+    </style:style>
+    <style:style style:name="OrgEquationTableColumn" style:family="table-column">
+      <style:table-column-properties style:rel-column-width="1*"/>
+    </style:style>
+    <style:style style:name="OrgFirstEquationFirstColumnTableCell" style:family="table-cell">
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
+    </style:style>
+    <style:style style:name="OrgEquationLastColumnTableCell" style:family="table-cell">
+      <style:table-cell-properties style:vertical-align="middle" fo:padding="0.159cm" fo:border-top="none" fo:border-bottom="none" fo:border-left="none" fo:border-right="none"/>
+    </style:style>
+    <style:style style:name="OrgEquationFirstColumnTableParagraph" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+      <style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/>
+    </style:style>
+    <style:style style:name="OrgEquationLastColumnTableParagraph" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+      <style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/>
+    </style:style>
+    <!-- END: Table styles for numbered equations -->
+
   </office:automatic-styles>
   </office:automatic-styles>
 
 
   <office:body>
   <office:body>
@@ -111,8 +133,8 @@
 	<text:sequence-decl text:display-outline-level="0" text:name="Text"/>
 	<text:sequence-decl text:display-outline-level="0" text:name="Text"/>
 	<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
 	<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
 	<text:sequence-decl text:display-outline-level="0" text:name="Equation"/>
 	<text:sequence-decl text:display-outline-level="0" text:name="Equation"/>
+	<text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
       </text:sequence-decls>
       </text:sequence-decls>
-
     </office:text>
     </office:text>
   </office:body>
   </office:body>
 </office:document-content>
 </office:document-content>

+ 24 - 4
contrib/odt/styles/OrgOdtStyles.xml

@@ -363,29 +363,49 @@
   </style:style>
   </style:style>
 
 
   <!-- Simple Images   -->
   <!-- Simple Images   -->
-  <style:style style:name="OrgSimpleGraphics" style:family="graphic" style:parent-style-name="Graphics">
+  <style:style style:name="OrgDisplayImage" style:family="graphic" style:parent-style-name="Graphics">
    <style:graphic-properties text:anchor-type="paragraph" style:wrap="none" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
    <style:graphic-properties text:anchor-type="paragraph" style:wrap="none" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
   </style:style>
   </style:style>
 
 
   <!-- Captioned Images  -->
   <!-- Captioned Images  -->
-  <style:style style:name="OrgCaptionedGraphics" style:family="graphic" style:parent-style-name="Graphics">
+  <style:style style:name="OrgCaptionedImage" style:family="graphic" style:parent-style-name="Graphics">
    <style:graphic-properties style:rel-width="100%" text:anchor-type="paragraph" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" style:run-through="foreground" style:wrap="none" style:vertical-pos="from-top" style:vertical-rel="paragraph-content" style:horizontal-pos="from-left" style:horizontal-rel="paragraph-content" fo:padding="0cm" fo:border="none" style:shadow="none"/>
    <style:graphic-properties style:rel-width="100%" text:anchor-type="paragraph" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" style:run-through="foreground" style:wrap="none" style:vertical-pos="from-top" style:vertical-rel="paragraph-content" style:horizontal-pos="from-left" style:horizontal-rel="paragraph-content" fo:padding="0cm" fo:border="none" style:shadow="none"/>
   </style:style>
   </style:style>
 
 
-  <style:style style:name="OrgCaptionFrame" style:family="graphic" style:parent-style-name="Frame">
+  <style:style style:name="OrgImageCaptionFrame" style:family="graphic" style:parent-style-name="Frame">
    <style:graphic-properties text:anchor-type="paragraph" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" style:wrap="none" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph" fo:padding="0cm" fo:border="none"/>
    <style:graphic-properties text:anchor-type="paragraph" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" style:wrap="none" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph" fo:padding="0cm" fo:border="none"/>
   </style:style>
   </style:style>
 
 
   <!-- Inlined Images -->
   <!-- Inlined Images -->
-  <style:style style:name="OrgInlineGraphics" style:family="graphic" style:parent-style-name="Graphics">
+  <style:style style:name="OrgInlineImage" style:family="graphic" style:parent-style-name="Graphics">
    <style:graphic-properties text:anchor-type="as-char" style:vertical-pos="top" style:vertical-rel="baseline" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
    <style:graphic-properties text:anchor-type="as-char" style:vertical-pos="top" style:vertical-rel="baseline" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
   </style:style>
   </style:style>
 
 
   <!-- Inline Formula -->
   <!-- Inline Formula -->
+  <style:style style:name="OrgFormula" style:family="graphic">
+    <style:graphic-properties text:anchor-type="as-char" svg:y="0cm" fo:margin-left="0.201cm" fo:margin-right="0.201cm" style:vertical-pos="middle" style:vertical-rel="text" style:shadow="none"/>
+  </style:style>
+
   <style:style style:name="OrgInlineFormula" style:family="graphic" style:parent-style-name="Formula">
   <style:style style:name="OrgInlineFormula" style:family="graphic" style:parent-style-name="Formula">
     <style:graphic-properties text:anchor-type="as-char" fo:margin-left="0.201cm" fo:margin-right="0.201cm" style:vertical-pos="middle" style:vertical-rel="text"/>
     <style:graphic-properties text:anchor-type="as-char" fo:margin-left="0.201cm" fo:margin-right="0.201cm" style:vertical-pos="middle" style:vertical-rel="text"/>
   </style:style>
   </style:style>
 
 
+  <style:style style:name="OrgInlineFormula" style:family="graphic" style:parent-style-name="Formula">
+    <style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" draw:ole-draw-aspect="1"/>
+  </style:style>
+
+  <style:style style:name="OrgDisplayFormula" style:family="graphic" style:parent-style-name="OrgFormula">
+    <style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph-content" draw:ole-draw-aspect="1"/>
+  </style:style>
+
+  <style:style style:name="OrgFormulaCaptionFrame" style:family="graphic" style:parent-style-name="Frame">
+    <style:graphic-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph-content" fo:padding="0cm" fo:border="none"/>
+  </style:style>
+
+  <style:style style:name="OrgCaptionedFormula" style:family="graphic" style:parent-style-name="OrgFormula">
+    <style:graphic-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" style:run-through="foreground" style:wrap="none" style:vertical-pos="from-top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:padding="0cm" fo:border="none" style:shadow="none" draw:ole-draw-aspect="1"/>
+  </style:style>
+
   <!-- Inline Tasks -->
   <!-- Inline Tasks -->
   <style:style style:name="OrgInlineTaskHeading" style:family="paragraph" style:parent-style-name="Caption" style:next-style-name="Text_20_body">
   <style:style style:name="OrgInlineTaskHeading" style:family="paragraph" style:parent-style-name="Caption" style:next-style-name="Text_20_body">
    <style:text-properties style:font-name="Arial1" fo:font-style="normal" fo:font-weight="bold"/>
    <style:text-properties style:font-name="Arial1" fo:font-style="normal" fo:font-weight="bold"/>

+ 1 - 1
lisp/ob-C.el

@@ -179,7 +179,7 @@ of the same value."
       (format "int %S = %S;" var val))
       (format "int %S = %S;" var val))
      ((floatp val)
      ((floatp val)
       (format "double %S = %S;" var val))
       (format "double %S = %S;" var val))
-     ((or (characterp val))
+     ((or (integerp val))
       (format "char %S = '%S';" var val))
       (format "char %S = '%S';" var val))
      ((stringp val)
      ((stringp val)
       (format "char %S[%d] = \"%s\";"
       (format "char %S[%d] = \"%s\";"

+ 24 - 12
lisp/ob-R.el

@@ -79,7 +79,8 @@
   "Execute a block of R code.
   "Execute a block of R code.
 This function is called by `org-babel-execute-src-block'."
 This function is called by `org-babel-execute-src-block'."
   (save-excursion
   (save-excursion
-    (let* ((result-type (cdr (assoc :result-type params)))
+    (let* ((result-params (cdr (assoc :result-params params)))
+	   (result-type (cdr (assoc :result-type params)))
            (session (org-babel-R-initiate-session
            (session (org-babel-R-initiate-session
 		     (cdr (assoc :session params)) params))
 		     (cdr (assoc :session params)) params))
 	   (colnames-p (cdr (assoc :colnames params)))
 	   (colnames-p (cdr (assoc :colnames params)))
@@ -88,7 +89,7 @@ This function is called by `org-babel-execute-src-block'."
 	   (full-body (org-babel-expand-body:R body params graphics-file))
 	   (full-body (org-babel-expand-body:R body params graphics-file))
 	   (result
 	   (result
 	    (org-babel-R-evaluate
 	    (org-babel-R-evaluate
-	     session full-body result-type
+	     session full-body result-type result-params
 	     (or (equal "yes" colnames-p)
 	     (or (equal "yes" colnames-p)
 		 (org-babel-pick-name
 		 (org-babel-pick-name
 		  (cdr (assoc :colname-names params)) colnames-p))
 		  (cdr (assoc :colname-names params)) colnames-p))
@@ -231,16 +232,15 @@ current code buffer."
 (defvar org-babel-R-write-object-command "{function(object,transfer.file){object;invisible(if(inherits(try({tfile<-tempfile();write.table(object,file=tfile,sep=\"\\t\",na=\"nil\",row.names=%s,col.names=%s,quote=FALSE);file.rename(tfile,transfer.file)},silent=TRUE),\"try-error\")){if(!file.exists(transfer.file))file.create(transfer.file)})}}(object=%s,transfer.file=\"%s\")")
 (defvar org-babel-R-write-object-command "{function(object,transfer.file){object;invisible(if(inherits(try({tfile<-tempfile();write.table(object,file=tfile,sep=\"\\t\",na=\"nil\",row.names=%s,col.names=%s,quote=FALSE);file.rename(tfile,transfer.file)},silent=TRUE),\"try-error\")){if(!file.exists(transfer.file))file.create(transfer.file)})}}(object=%s,transfer.file=\"%s\")")
 
 
 (defun org-babel-R-evaluate
 (defun org-babel-R-evaluate
-  (session body result-type column-names-p row-names-p)
+  (session body result-type result-params column-names-p row-names-p)
   "Evaluate R code in BODY."
   "Evaluate R code in BODY."
-  (if session
-      (org-babel-R-evaluate-session
-       session body result-type column-names-p row-names-p)
-    (org-babel-R-evaluate-external-process
-     body result-type column-names-p row-names-p)))
+  (funcall (if session
+	       #'org-babel-R-evaluate-session
+	     #'org-babel-R-evaluate-external-process)
+	   body result-type result-params column-names-p row-names-p))
 
 
 (defun org-babel-R-evaluate-external-process
 (defun org-babel-R-evaluate-external-process
-  (body result-type column-names-p row-names-p)
+  (body result-type result-params column-names-p row-names-p)
   "Evaluate BODY in external R process.
   "Evaluate BODY in external R process.
 If RESULT-TYPE equals 'output then return standard output as a
 If RESULT-TYPE equals 'output then return standard output as a
 string. If RESULT-TYPE equals 'value then return the value of the
 string. If RESULT-TYPE equals 'value then return the value of the
@@ -257,11 +257,17 @@ last statement in BODY, as elisp."
 			       (format "{function ()\n{\n%s\n}}()" body)
 			       (format "{function ()\n{\n%s\n}}()" body)
 			       (org-babel-process-file-name tmp-file 'noquote)))
 			       (org-babel-process-file-name tmp-file 'noquote)))
        (org-babel-R-process-value-result
        (org-babel-R-process-value-result
-	(org-babel-import-elisp-from-file tmp-file '(16)) column-names-p)))
+	(if (or (member "scalar" result-params)
+		(member "verbatim" result-params))
+	    (with-temp-buffer
+	      (insert-file-contents tmp-file)
+	      (buffer-string))
+	  (org-babel-import-elisp-from-file tmp-file '(16)))
+	column-names-p)))
     (output (org-babel-eval org-babel-R-command body))))
     (output (org-babel-eval org-babel-R-command body))))
 
 
 (defun org-babel-R-evaluate-session
 (defun org-babel-R-evaluate-session
-  (session body result-type column-names-p row-names-p)
+  (session body result-type result-params column-names-p row-names-p)
   "Evaluate BODY in SESSION.
   "Evaluate BODY in SESSION.
 If RESULT-TYPE equals 'output then return standard output as a
 If RESULT-TYPE equals 'output then return standard output as a
 string. If RESULT-TYPE equals 'value then return the value of the
 string. If RESULT-TYPE equals 'value then return the value of the
@@ -283,7 +289,13 @@ last statement in BODY, as elisp."
 		  "FALSE")
 		  "FALSE")
 		".Last.value" (org-babel-process-file-name tmp-file 'noquote)))
 		".Last.value" (org-babel-process-file-name tmp-file 'noquote)))
        (org-babel-R-process-value-result
        (org-babel-R-process-value-result
-	(org-babel-import-elisp-from-file tmp-file '(16))  column-names-p)))
+	(if (or (member "scalar" result-params)
+		(member "verbatim" result-params))
+	    (with-temp-buffer
+	      (insert-file-contents tmp-file)
+	      (buffer-string))
+	  (org-babel-import-elisp-from-file tmp-file '(16)))
+	column-names-p)))
     (output
     (output
      (mapconcat
      (mapconcat
       #'org-babel-chomp
       #'org-babel-chomp

+ 27 - 16
lisp/ob-tangle.el

@@ -95,6 +95,14 @@ controlled by the :comments header argument."
   :group 'org-babel
   :group 'org-babel
   :type 'string)
   :type 'string)
 
 
+(defcustom org-babel-process-comment-text #'org-babel-trim
+  "Function called to process raw Org-mode text collected to be
+inserted as comments in tangled source-code files.  The function
+should take a single string argument and return a string
+result.  The default value is `org-babel-trim'."
+  :group 'org-babel
+  :type 'function)
+
 (defun org-babel-find-file-noselect-refresh (file)
 (defun org-babel-find-file-noselect-refresh (file)
   "Find file ensuring that the latest changes on disk are
   "Find file ensuring that the latest changes on disk are
 represented in the file."
 represented in the file."
@@ -345,16 +353,20 @@ code blocks by language."
 		    (when (or (string= "both" (cdr (assoc :comments params)))
 		    (when (or (string= "both" (cdr (assoc :comments params)))
 			      (string= "org" (cdr (assoc :comments params))))
 			      (string= "org" (cdr (assoc :comments params))))
 		      ;; from the previous heading or code-block end
 		      ;; from the previous heading or code-block end
-		      (buffer-substring
-		       (max (condition-case nil
-				(save-excursion
-				  (org-back-to-heading t) (point))
-			      (error 0))
-			    (save-excursion
-			      (re-search-backward
-			       org-babel-src-block-regexp nil t)
-			      (match-end 0)))
-		       (point))))
+		      (funcall
+		       org-babel-process-comment-text
+		       (buffer-substring
+			(max (condition-case nil
+				 (save-excursion
+				   (org-back-to-heading t)  ; sets match data
+				   (match-end 0))
+			       (error (point-min)))
+			     (save-excursion
+			       (if (re-search-backward
+				    org-babel-src-block-regexp nil t)
+				   (match-end 0)
+				 (point-min))))
+			(point)))))
 		   by-lang)
 		   by-lang)
 	      ;; add the spec for this block to blocks under it's language
 	      ;; add the spec for this block to blocks under it's language
 	      (setq by-lang (cdr (assoc src-lang blocks)))
 	      (setq by-lang (cdr (assoc src-lang blocks)))
@@ -396,12 +408,11 @@ form
 				     (eval el))))
 				     (eval el))))
 			    '(start-line file link source-name))))
 			    '(start-line file link source-name))))
     (flet ((insert-comment (text)
     (flet ((insert-comment (text)
-            (let ((text (org-babel-trim text)))
-	      (when (and comments (not (string= comments "no"))
-			 (> (length text) 0))
-		(when padline (insert "\n"))
-		(comment-region (point) (progn (insert text) (point)))
-		(end-of-line nil) (insert "\n")))))
+            (when (and comments (not (string= comments "no"))
+		       (> (length text) 0))
+	      (when padline (insert "\n"))
+	      (comment-region (point) (progn (insert text) (point)))
+	      (end-of-line nil) (insert "\n"))))
       (when comment (insert-comment comment))
       (when comment (insert-comment comment))
       (when link-p
       (when link-p
 	(insert-comment
 	(insert-comment

+ 13 - 4
lisp/ob.el

@@ -220,8 +220,16 @@ Returns a list
 	    (when (match-string 6)
 	    (when (match-string 6)
 	      (setf (nth 2 info) ;; merge functional-syntax vars and header-args
 	      (setf (nth 2 info) ;; merge functional-syntax vars and header-args
 		    (org-babel-merge-params
 		    (org-babel-merge-params
-		     (mapcar (lambda (ref) (cons :var ref))
-			     (org-babel-ref-split-args (match-string 6)))
+		     (mapcar
+		      (lambda (ref) (cons :var ref))
+		      (mapcar
+		       (lambda (var) ;; check that each variable is initialized
+			 (if (string-match ".+=.+" var)
+			     var
+			   (error
+			    "variable \"%s\"%s must be assigned a default value"
+			    var (if name (format " in block \"%s\"" name) ""))))
+		       (org-babel-ref-split-args (match-string 6))))
 		     (nth 2 info))))))
 		     (nth 2 info))))))
       ;; inline source block
       ;; inline source block
       (when (org-babel-get-inline-src-block-matches)
       (when (org-babel-get-inline-src-block-matches)
@@ -550,6 +558,7 @@ arguments and pop open the results in a preview buffer."
   (interactive)
   (interactive)
   ;; TODO: report malformed code block
   ;; TODO: report malformed code block
   ;; TODO: report incompatible combinations of header arguments
   ;; TODO: report incompatible combinations of header arguments
+  ;; TODO: report uninitialized variables
   (let ((too-close 2)) ;; <- control closeness to report potential match
   (let ((too-close 2)) ;; <- control closeness to report potential match
     (dolist (header (mapcar (lambda (arg) (substring (symbol-name (car arg)) 1))
     (dolist (header (mapcar (lambda (arg) (substring (symbol-name (car arg)) 1))
 			    (and (org-babel-where-is-src-block-head)
 			    (and (org-babel-where-is-src-block-head)
@@ -1795,8 +1804,8 @@ Later elements of PLISTS override the values of previous elements.
 This takes into account some special considerations for certain
 This takes into account some special considerations for certain
 parameters when merging lists."
 parameters when merging lists."
   (let ((results-exclusive-groups
   (let ((results-exclusive-groups
-	 '(("file" "list" "vector" "table" "scalar" "verbatim" "raw" "org"
-            "html" "latex" "code" "pp" "wrap")
+	 '(("file" "list" "vector" "table" "scalar" "verbatim")
+	   ("raw" "org" "html" "latex" "code" "pp" "wrap")
 	   ("replace" "silent" "append" "prepend")
 	   ("replace" "silent" "append" "prepend")
 	   ("output" "value")))
 	   ("output" "value")))
 	(exports-exclusive-groups
 	(exports-exclusive-groups

+ 1 - 1
lisp/org-footnote.el

@@ -249,7 +249,7 @@ footnote text is included and defined locally.
 
 
 The return value will be nil if not at a footnote definition, and a list with
 The return value will be nil if not at a footnote definition, and a list with
 label, start, end and definition of the footnote otherwise."
 label, start, end and definition of the footnote otherwise."
-  (when (org-footnote-in-valid-context-p)
+  (when (save-excursion (beginning-of-line) (org-footnote-in-valid-context-p))
     (save-excursion
     (save-excursion
       (end-of-line)
       (end-of-line)
       (let ((lim (save-excursion (re-search-backward
       (let ((lim (save-excursion (re-search-backward

+ 15 - 0
testing/examples/babel-dangerous.org

@@ -0,0 +1,15 @@
+#+Title: dangerous code block examples which should be isolated
+#+OPTIONS: ^:nil
+
+* no default value for vars
+  :PROPERTIES:
+  :ID:       f2df5ba6-75fa-4e6b-8441-65ed84963627
+  :END:
+
+There is no default value assigned to =x= variable. This is not permitted
+anymore.
+
+#+source: carre(x)
+#+begin_src python
+  return x*x
+#+end_src

+ 19 - 0
testing/examples/babel.org

@@ -289,3 +289,22 @@ src_sh{echo "One"} block at start of line
  One spaced block in  src_sh{ echo "middle" } of line 
  One spaced block in  src_sh{ echo "middle" } of line 
 src_sh{echo 2} blocks on the src_emacs-lisp{"same"} line
 src_sh{echo 2} blocks on the src_emacs-lisp{"same"} line
  Inline block with src_sh[:results silent]{ echo "parameters" }.
  Inline block with src_sh[:results silent]{ echo "parameters" }.
+* returning file names -- interpreted as lists
+  :PROPERTIES:
+  :ID:       a73a2ab6-b8b2-4c0e-ae7f-23ad14eab7bc
+  :END:
+
+#+begin_src sh :results scalar
+  echo "[[file:./cv.cls]]"
+#+end_src
+
+#+results:
+: [[file:./cv.cls]]
+
+#+begin_src sh :results raw scalar
+   echo "[[file:./cv.cls]]"
+#+end_src
+
+#+results:
+[[file:./cv.cls]]
+

+ 22 - 1
testing/lisp/test-ob.el

@@ -1,6 +1,6 @@
 ;;; test-ob.el --- tests for ob.el
 ;;; test-ob.el --- tests for ob.el
 
 
-;; Copyright (c) 2010 Eric Schulte
+;; Copyright (c) 2010, 2011 Eric Schulte
 ;; Authors: Eric Schulte, Martyn Jago
 ;; Authors: Eric Schulte, Martyn Jago
 
 
 ;; Released under the GNU General Public License version 3
 ;; Released under the GNU General Public License version 3
@@ -409,6 +409,27 @@
       (should (string= (concat test-line " =\"x\"=")
       (should (string= (concat test-line " =\"x\"=")
 		       (buffer-substring-no-properties (point-min) (point-max)))))))
 		       (buffer-substring-no-properties (point-min) (point-max)))))))
 
 
+(ert-deftest test-org-babel/combining-scalar-and-raw-result-types ()
+  (flet ((next-result ()
+		      (org-babel-next-src-block)
+		      (org-babel-execute-src-block)
+		      (goto-char (org-babel-where-is-src-block-result))
+		      (forward-line 1)))
+    (org-test-at-id "a73a2ab6-b8b2-4c0e-ae7f-23ad14eab7bc"
+      (next-result)
+      (should (org-babel-in-example-or-verbatim))
+      (next-result)
+      (should (not (org-babel-in-example-or-verbatim))))))
+
+(ert-deftest test-org-babel/no-defaut-value-for-var ()
+  "Test that the absence of a default value for a variable DOES THROW
+  a proper error."
+  (org-test-at-id "f2df5ba6-75fa-4e6b-8441-65ed84963627"
+    (org-babel-next-src-block)
+    (let ((err
+	   (should-error (org-babel-execute-src-block) :type 'error)))
+      (should (equal '(error "variable \"x\" in block \"carre\" must be assigned a default value") err)))))
+
 (provide 'test-ob)
 (provide 'test-ob)
 
 
 ;;; test-ob ends here
 ;;; test-ob ends here

+ 1 - 1
testing/lisp/test-org.el

@@ -82,7 +82,7 @@
   (should
   (should
    (string=
    (string=
     "àâçèéêîôùû"
     "àâçèéêîôùû"
-    (org-link-unescape "%E0%E2%E7%E8%E9%EA%EE%F4%F9%FB"))))
+        (decode-coding-string (org-link-unescape "%E0%E2%E7%E8%E9%EA%EE%F4%F9%FB") 'latin-1))))
 
 
 (ert-deftest test-org/org-link-escape-url-with-escaped-char ()
 (ert-deftest test-org/org-link-escape-url-with-escaped-char ()
   "Escape and unscape a URL that includes an escaped char.
   "Escape and unscape a URL that includes an escaped char.

+ 41 - 1
testing/org-test.el

@@ -4,10 +4,14 @@
 ;; Authors:
 ;; Authors:
 ;;     Sebastian Rose, Hannover, Germany, sebastian_rose gmx de
 ;;     Sebastian Rose, Hannover, Germany, sebastian_rose gmx de
 ;;     Eric Schulte, Santa Fe, New Mexico, USA, schulte.eric gmail com
 ;;     Eric Schulte, Santa Fe, New Mexico, USA, schulte.eric gmail com
+;;     David Maus, Brunswick, Germany, dmaus ictsoc de
 
 
 ;; Released under the GNU General Public License version 3
 ;; Released under the GNU General Public License version 3
 ;; see: http://www.gnu.org/licenses/gpl-3.0.html
 ;; see: http://www.gnu.org/licenses/gpl-3.0.html
 
 
+;; Definition of `special-mode' copied from Emacs23's simple.el to be
+;; provide a testing environment for Emacs22.
+
 ;;;; Comments:
 ;;;; Comments:
 
 
 ;; Interactive testing for Org mode.
 ;; Interactive testing for Org mode.
@@ -31,7 +35,7 @@
 		       (or load-file-name buffer-file-name)))))
 		       (or load-file-name buffer-file-name)))))
    (let ((org-lisp-dir (expand-file-name
    (let ((org-lisp-dir (expand-file-name
    		       (concat org-test-dir "../lisp"))))
    		       (concat org-test-dir "../lisp"))))
-     (unless (member 'features "org")
+     (unless (featurep 'org)
        (setq load-path (cons org-lisp-dir load-path))
        (setq load-path (cons org-lisp-dir load-path))
        (org-babel-do-load-languages
        (org-babel-do-load-languages
 	'org-babel-load-languages '((sh . t)))))
 	'org-babel-load-languages '((sh . t)))))
@@ -41,6 +45,25 @@
 		      (expand-file-name "jump" org-test-dir)
 		      (expand-file-name "jump" org-test-dir)
 		      load-path))))
 		      load-path))))
     (require 'cl)
     (require 'cl)
+    (when (= emacs-major-version 22)
+      (defvar special-mode-map
+	(let ((map (make-sparse-keymap)))
+	  (suppress-keymap map)
+	  (define-key map "q" 'quit-window)
+	  (define-key map " " 'scroll-up)
+	  (define-key map "\C-?" 'scroll-down)
+	  (define-key map "?" 'describe-mode)
+	  (define-key map "h" 'describe-mode)
+	  (define-key map ">" 'end-of-buffer)
+	  (define-key map "<" 'beginning-of-buffer)
+	  (define-key map "g" 'revert-buffer)
+	  (define-key map "z" 'kill-this-buffer)
+	  map))
+
+      (put 'special-mode 'mode-class 'special)
+      (define-derived-mode special-mode nil "Special"
+	"Parent major mode from which special major modes should inherit."
+	(setq buffer-read-only t)))
     (require 'ert)
     (require 'ert)
     (require 'ert-x)
     (require 'ert-x)
     (when (file-exists-p
     (when (file-exists-p
@@ -138,6 +161,23 @@ files."
      (re-search-forward (regexp-quote ,marker))
      (re-search-forward (regexp-quote ,marker))
      ,@body))
      ,@body))
 
 
+(defmacro org-test-with-temp-text (text &rest body)
+  "Run body in a temporary buffer with Org-mode as the active
+mode holding TEXT.  If the string \"<point>\" appears in TEXT
+then remove it and place the point there before running BODY."
+  (declare (indent 1))
+  `(with-temp-buffer
+     (org-mode)
+     ,(let ((point (string-match (regexp-quote "<point>") text)))
+	(if point
+	    `(progn
+	       (insert `(replace-match "" nil nil text))
+	       (goto-char ,(match-beginning 0)))
+	  `(progn
+	     (insert ,text)
+	     (goto-char (point-min)))))
+     ,@body))
+
 
 
 ;;; Navigation Functions
 ;;; Navigation Functions
 (when (featurep 'jump)
 (when (featurep 'jump)