org-taskjuggler.el 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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 180
  67. "."
  68. :group 'org-export-taskjuggler
  69. :type 'integer)
  70. (defcustom org-export-taskjuggler-default-reports
  71. '("taskreport \"Gantt Chart\" {
  72. headline \"Project Gantt Chart\"
  73. columns hierarchindex, name, start, end, effort, duration, completed, chart
  74. timeformat \"%a %Y-%m-%d\"
  75. loadunit days
  76. }"
  77. "resourcereport \"Resource Graph\" {
  78. headline \"Resource Allocation Graph\"
  79. columns no, name, rate, utilization, freeload, chart
  80. loadunit days
  81. hidetask 1
  82. }")
  83. ""
  84. :group 'org-export-taskjuggler
  85. :type '(repeat (string :tag "Report")))
  86. ;;; Hooks
  87. (defvar org-export-taskjuggler-final-hook nil
  88. "Hook run at the end of TaskJuggler export, in the new buffer.")
  89. ;;; Autoload functions:
  90. ;;;###autoload
  91. (defun org-export-as-taskjuggler ()
  92. "Export the current buffer as a TaskJuggler file."
  93. (interactive)
  94. (message "Exporting...")
  95. (let* ((tasks
  96. (org-map-entries '(org-taskjuggler-components)
  97. org-export-taskjuggler-project-tag nil 'archive 'comment))
  98. (resources
  99. (org-map-entries '(org-taskjuggler-components)
  100. org-export-taskjuggler-resource-tag nil 'archive 'comment))
  101. (filename (expand-file-name
  102. (concat
  103. (file-name-sans-extension
  104. (file-name-nondirectory buffer-file-name))
  105. org-export-taskjuggler-extension)))
  106. (buffer (find-file-noselect filename))
  107. (old-level 0)
  108. (current-id 0)
  109. task resource)
  110. ;; add a default resource
  111. (unless resources
  112. (setq resources
  113. `((("ID" . ,(user-login-name))
  114. ("headline" . ,user-full-name)
  115. ("level" . 1)))))
  116. ;; add a default allocation to the first task if none was given
  117. (unless (assoc "allocate" (car tasks))
  118. (let ((task (car tasks))
  119. (resource-id (cdr (assoc "ID" (car resources)))))
  120. (setcar tasks (push (cons "allocate" resource-id) task))))
  121. ;; add a default start date to the first task if none was given
  122. (unless (assoc "start" (car tasks))
  123. (let ((task (car tasks))
  124. (time-string (format-time-string "%Y-%m-%d")))
  125. (setcar tasks (push (cons "start" time-string) task))))
  126. ;; add a default end date to the first task if none was given
  127. (unless (assoc "end" (car tasks))
  128. (let* ((task (car tasks))
  129. (now (current-time))
  130. (duration
  131. (days-to-time org-export-taskjuggler-default-project-duration))
  132. (time-string
  133. (format-time-string "%Y-%m-%d" (time-add now duration))))
  134. (setcar tasks (push (cons "end" time-string) task))))
  135. ;; add a default version if none was given
  136. (unless (assoc "version" (car tasks))
  137. (let ((task (car tasks))
  138. (version org-export-taskjuggler-default-project-version))
  139. (setcar tasks (push (cons "version" version) task))))
  140. (with-current-buffer buffer
  141. (erase-buffer)
  142. (org-taskjuggler-open-project (car tasks))
  143. (dolist (resource resources)
  144. (let ((level (cdr (assoc "level" resource))))
  145. (org-taskjuggler-close-maybe level)
  146. (org-taskjuggler-open-resource resource)
  147. (setq old-level level)))
  148. (org-taskjuggler-close-maybe 1)
  149. (setq old-level 0)
  150. (dolist (task tasks)
  151. (let ((level (cdr (assoc "level" task))))
  152. (org-taskjuggler-close-maybe level)
  153. (org-taskjuggler-open-task task)
  154. (setq old-level level)))
  155. (org-taskjuggler-close-maybe 1)
  156. (org-taskjuggler-insert-reports))))
  157. (defun org-taskjuggler-components ()
  158. (let* ((props (org-entry-properties))
  159. (components (org-heading-components))
  160. (level (car components))
  161. (headline (nth 4 components)))
  162. (push (cons "level" level) props)
  163. (push (cons "headline" headline) props)))
  164. (defun org-taskjuggler-clean-id (id)
  165. (and id (replace-regexp-in-string "[^a-zA-Z0-9_]" "_" id)))
  166. (defun org-taskjuggler-open-project (project)
  167. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" project))))
  168. (headline (cdr (assoc "headline" project)))
  169. (version (cdr (assoc "version" project)))
  170. (start (cdr (assoc "start" project)))
  171. (end (cdr (assoc "end" project))))
  172. (insert
  173. (concat
  174. "project "
  175. (or id "FIXME")
  176. " \"" headline "\" \"" version "\" " start " - " end " {\n " "}\n"))))
  177. (defun org-taskjuggler-open-resource (resource)
  178. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" resource))))
  179. (headline (cdr (assoc "headline" resource))))
  180. (insert
  181. (concat "resource " id " \"" headline "\" {\n "))))
  182. (defun org-taskjuggler-clean-effort (effort)
  183. (cond
  184. ((null effort) effort)
  185. ((string-match "\\([0-9]+\\):\\([0-9]+\\)" effort)
  186. (concat (match-string 1 effort) "." (match-string 2 effort) "h"))
  187. ((string-match "\\([0-9]+\\).\\([0-9]+\\)" effort) (concat effort "d"))
  188. (t (error "Not a valid effort (%s)" effort))))
  189. (defun org-taskjuggler-open-task (task)
  190. (let ((id (org-taskjuggler-clean-id (cdr (assoc "ID" task))))
  191. (headline (cdr (assoc "headline" task)))
  192. (effort (org-taskjuggler-clean-effort (cdr (assoc org-effort-property task))))
  193. (depends (cdr (assoc "depends" task)))
  194. (allocate (cdr (assoc "allocate" task)))
  195. (account (cdr (assoc "account" task)))
  196. (start (cdr (assoc "start" task)))
  197. (complete (cdr (assoc "complete" task)))
  198. (note (cdr (assoc "note" task)))
  199. (priority (cdr (assoc "priority" task))))
  200. (insert
  201. (concat
  202. "task "
  203. (or id (concat "id" (number-to-string (incf current-id))))
  204. " \"" headline "\" {"
  205. (and effort (concat "\n effort " effort))
  206. (and depends (concat "\n depends " depends))
  207. (and allocate (concat "\n purge allocations\n allocate " allocate))
  208. (and account (concat "\n account " account))
  209. (and start (concat "\n start " start))
  210. (and complete (concat "\n complete " complete))
  211. (and note (concat "\n note " note))
  212. (and priority (concat "\n priority " priority))
  213. "\n"))))
  214. (defun org-taskjuggler-close-maybe (level)
  215. (while (> old-level level)
  216. (insert "}\n")
  217. (setq old-level (1- old-level)))
  218. (when (= old-level level)
  219. (insert "}\n")))
  220. (defun org-taskjuggler-insert-reports ()
  221. (let (report)
  222. (dolist (report org-export-taskjuggler-default-reports)
  223. (insert report "\n"))))
  224. (provide 'org-taskjuggler)
  225. ;; arch-tag: a24a127c-d365-4c2a-9e9b-f7dcb0ebfdc3
  226. ;;; org-taskjuggler.el ends here