org-taskjuggler.el 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. ;;; org-taskjuggler.el --- TaskJuggler exporter for org-mode
  2. ;;
  3. ;; Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  4. ;;
  5. ;; Emacs Lisp Archive Entry
  6. ;; Filename: org-taskjuggler.el
  7. ;; Version: 6.34trans
  8. ;; Author: Christian Egli
  9. ;; Maintainer: Christian Egli
  10. ;; Keywords: org, taskjuggler, project planning
  11. ;; Description: Converts an org-mode buffer into a taskjuggler project plan
  12. ;; URL:
  13. ;; This file is part of GNU Emacs.
  14. ;; GNU Emacs is free software: you can redistribute it and/or modify
  15. ;; it under the terms of the GNU General Public License as published by
  16. ;; the Free Software Foundation, either version 3 of the License, or
  17. ;; (at your option) any later version.
  18. ;; GNU Emacs is distributed in the hope that it will be useful,
  19. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. ;; GNU General Public License for more details.
  22. ;; You should have received a copy of the GNU General Public License
  23. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  24. ;; Commentary:
  25. ;;
  26. ;; This library implements a TaskJuggler exporter for org-mode.
  27. ;;
  28. ;; The interactive functions are similar to those of the HTML and LaTeX
  29. ;; exporters:
  30. ;;
  31. ;; M-x `org-export-as-taskjuggler'
  32. ;; M-x `org-export-as-taskjuggler-and-open'
  33. ;; M-x `org-export-as-taskjuggler-batch'
  34. ;; M-x `org-export-as-taskjuggler-to-buffer'
  35. ;; M-x `org-export-region-as-taskjuggler'
  36. ;; M-x `org-replace-region-by-taskjuggler'
  37. ;;
  38. ;;; Code:
  39. (eval-when-compile
  40. (require 'cl))
  41. (require 'org)
  42. (require 'org-exp)
  43. ;;; Variables:
  44. (declare-function org-id-find-id-file "org-id" (id))
  45. ;;; User variables:
  46. (defgroup org-export-taskjuggler nil
  47. "Options for exporting Org-mode files to TaskJuggler."
  48. :tag "Org Export TaskJuggler"
  49. :group 'org-export)
  50. (defcustom org-export-taskjuggler-extension ".tjp"
  51. "Extension of TaskJuggler files."
  52. :group 'org-export-taskjuggler
  53. :type 'string)
  54. (defcustom org-export-taskjuggler-project-tag "project"
  55. "."
  56. :group 'org-export-taskjuggler
  57. :type 'string)
  58. (defcustom org-export-taskjuggler-resource-tag "resource"
  59. "."
  60. :group 'org-export-taskjuggler
  61. :type 'string)
  62. (defcustom org-export-taskjuggler-default-project-version "1.0"
  63. "."
  64. :group 'org-export-taskjuggler
  65. :type 'string)
  66. (defcustom org-export-taskjuggler-default-project-duration 365
  67. "."
  68. :group 'org-export-taskjuggler
  69. :type 'integer)
  70. ;;; Hooks
  71. (defvar org-export-taskjuggler-final-hook nil
  72. "Hook run at the end of TaskJuggler export, in the new buffer.")
  73. ;;; Autoload functions:
  74. ;;;###autoload
  75. (defun org-export-as-taskjuggler ()
  76. "Export the current buffer as a TaskJuggler file."
  77. (interactive)
  78. (message "Exporting...")
  79. (let* ((tasks
  80. (org-map-entries '(org-taskjuggler-components)
  81. org-export-taskjuggler-project-tag nil 'archive 'comment))
  82. (resources
  83. (org-map-entries '(org-taskjuggler-components)
  84. org-export-taskjuggler-resource-tag nil 'archive 'comment))
  85. (filename (expand-file-name
  86. (concat
  87. (file-name-sans-extension
  88. (file-name-nondirectory buffer-file-name))
  89. org-export-taskjuggler-extension)))
  90. (buffer (find-file-noselect filename))
  91. (old-level 0)
  92. (current-id 0)
  93. task resource)
  94. ;; add a default resource
  95. (unless resources
  96. (setq resources
  97. `((("ID" . ,(user-login-name))
  98. ("headline" . ,user-full-name)
  99. ("level" . 1)))))
  100. ;; add a default allocation to the first task if none was given
  101. (unless (assoc "allocate" (car tasks))
  102. (let ((task (car tasks))
  103. (resource-id (cdr (assoc "ID" (car resources)))))
  104. (setcar tasks (push (cons "allocate" resource-id) task))))
  105. ;; add a default start date to the first task if none was given
  106. (unless (assoc "start" (car tasks))
  107. (let ((task (car tasks))
  108. (time-string (format-time-string "%Y-%m-%d")))
  109. (setcar tasks (push (cons "start" time-string) task))))
  110. ;; add a default end date to the first task if none was given
  111. (unless (assoc "end" (car tasks))
  112. (let* ((task (car tasks))
  113. (now (current-time))
  114. (duration
  115. (days-to-time org-export-taskjuggler-default-project-duration))
  116. (time-string
  117. (format-time-string "%Y-%m-%d" (time-add now duration))))
  118. (setcar tasks (push (cons "end" time-string) task))))
  119. ;; add a default version if none was given
  120. (unless (assoc "version" (car tasks))
  121. (let ((task (car tasks))
  122. (version org-export-taskjuggler-default-project-version))
  123. (setcar tasks (push (cons "version" version) task))))
  124. (with-current-buffer buffer
  125. (erase-buffer)
  126. (org-taskjuggler-open-project (car tasks))
  127. (dolist (resource resources nil)
  128. (let ((level (cdr (assoc "level" resource))))
  129. (org-taskjuggler-close-maybe level)
  130. (org-taskjuggler-open-resource resource)
  131. (setq old-level level)))
  132. (org-taskjuggler-close-maybe 1)
  133. (setq old-level 0)
  134. (dolist (task tasks nil)
  135. (let ((level (cdr (assoc "level" task))))
  136. (org-taskjuggler-close-maybe level)
  137. (org-taskjuggler-open-task task)
  138. (setq old-level level)))
  139. (org-taskjuggler-close-maybe 1))))
  140. (defun org-taskjuggler-components ()
  141. (let* ((props (org-entry-properties))
  142. (components (org-heading-components))
  143. (level (car components))
  144. (headline (nth 4 components)))
  145. (push (cons "level" level) props)
  146. (push (cons "headline" headline) props)))
  147. (defun org-taskjuggler-clean-id (id)
  148. (and id (replace-regexp-in-string "[^a-zA-Z0-9_]" "_" id)))
  149. (defun org-taskjuggler-open-project (project)
  150. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" project))))
  151. (headline (cdr (assoc "headline" project)))
  152. (version (cdr (assoc "version" project)))
  153. (start (cdr (assoc "start" project)))
  154. (end (cdr (assoc "end" project))))
  155. (insert
  156. (concat
  157. "project "
  158. (or id "FIXME")
  159. " \"" headline "\" \"" version "\" " start " - " end " {\n " "}\n"))))
  160. (defun org-taskjuggler-open-resource (resource)
  161. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" resource))))
  162. (headline (cdr (assoc "headline" resource))))
  163. (insert
  164. (concat "resource " id " \"" headline "\" {\n "))))
  165. (defun org-taskjuggler-clean-effort (effort)
  166. (cond
  167. ((null effort) effort)
  168. ((string-match "\\([0-9]+\\):\\([0-9]+\\)" effort)
  169. (concat (match-string 1 effort) "." (match-string 2 effort) "h"))
  170. ((string-match "\\([0-9]+\\).\\([0-9]+\\)" effort) (concat effort "d"))
  171. (t (error "Not a valid effort (%s)" effort))))
  172. (defun org-taskjuggler-open-task (task)
  173. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" task))))
  174. (headline (cdr (assoc "headline" task)))
  175. (effort (org-taskjuggler-clean-effort(cdr (assoc org-effort-property task))))
  176. (depends (cdr (assoc "depends" task)))
  177. (allocate (cdr (assoc "allocate" task)))
  178. (account (cdr (assoc "account" task)))
  179. (start (cdr (assoc "start" task)))
  180. (complete (cdr (assoc "complete" task)))
  181. (note (cdr (assoc "note" task)))
  182. (priority (cdr (assoc "priority" task))))
  183. (insert
  184. (concat
  185. "task "
  186. (or id (concat "id" (number-to-string (setq current-id (1+ current-id)))))
  187. " \"" headline "\" {"
  188. (and effort (concat "\n effort " effort))
  189. (and depends (concat "\n depends " depends))
  190. (and allocate (concat "\n purge allocations\n allocate " allocate))
  191. (and account (concat "\n account " account))
  192. (and start (concat "\n start " start))
  193. (and complete (concat "\n complete " complete))
  194. (and note (concat "\n note " note))
  195. (and priority (concat "\n priority " priority))
  196. "\n"))))
  197. (defun org-taskjuggler-close-maybe (level)
  198. (while (> old-level level)
  199. (insert "}\n")
  200. (setq old-level (1- old-level)))
  201. (when (= old-level level)
  202. (insert "}\n")))
  203. (provide 'org-taskjuggler)
  204. ;; arch-tag: a24a127c-d365-4c2a-9e9b-f7dcb0ebfdc3
  205. ;;; org-taskjuggler.el ends here