Here are a couple of patches for org-taskjuggler.el My main goals with these were to: - be able to leverage SCHEDULE/DEADLINE information, so as to be able to leverage org timelines in complement to the reports - be able to #+BIND some of the exporter variables (such as the preamble) - be able to define reports in the org file itself, without having to mess with a custom variable Any feedback is highly welcome. Thanks, Yann. Yann Hodique (10): org-taskjuggler: make task and resource properties customizable org-taskjuggler: properly install local variables at export time org-taskjuggler: make use of org properties org-taskjuggler: task with end-only is also a milestone (deadline) org-taskjuggler: introduce a global header, for early macros org-taskjuggler: use project end date, if specified org-taskjuggler: make project umbrella task optional org-taskjuggler: disambiguate "headline", as it's also a valid taskjuggler property org-taskjuggler: allow reports definition from within the org file org-taskjuggler: update doc to reflect latest changes doc/org.texi | 48 ++++++++++------ lisp/org-taskjuggler.el | 145 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 149 insertions(+), 44 deletions(-) -- 1.7.11.3
* org-taskjuggler.el (org-export-taskjuggler-valid-task-attributes): new custom variable (org-export-taskjuggler-valid-resource-attributes): new custom variable --- lisp/org-taskjuggler.el | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 4409013..3c56630 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -240,6 +240,23 @@ but before any resource and task declarations." :version "24.1" :type '(string :tag "Preamble")) +(defcustom org-export-taskjuggler-valid-task-attributes + '(account start note duration endbuffer endcredit end + flags journalentry length limits maxend maxstart minend + minstart period reference responsible scheduling + startbuffer startcredit statusnote) + "Valid attributes for Taskjuggler tasks. If one of these + appears as a property for a headline, it will be exported with + the corresponding task." + :group 'org-export-taskjuggler) + +(defcustom org-export-taskjuggler-valid-resource-attributes + '(limits vacation shift booking efficiency journalentry rate) + "Valid attributes for Taskjuggler resources. If one of these + appears as a property for a headline, it will be exported with + the corresponding resource." + :group 'org-export-taskjuggler) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -614,7 +631,7 @@ is defined it will calculate a unique id for the resource using (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) (headline (cdr (assoc "headline" resource))) - (attributes '(limits vacation shift booking efficiency journalentry rate))) + (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat "resource " id " \"" headline "\" {\n " @@ -655,11 +672,7 @@ org-mode priority string." (cdr (assoc "duration" task)) (cdr (assoc "end" task)) (cdr (assoc "period" task))))))) - (attributes - '(account start note duration endbuffer endcredit end - flags journalentry length maxend maxstart minend - minstart period reference responsible scheduling - startbuffer startcredit statusnote))) + (attributes org-export-taskjuggler-valid-task-attributes)) (insert (concat "task " unique-id " \"" headline "\" {\n" -- 1.7.11.3
* org-taskjuggler.el (org-export-as-taskjuggler): compute opt-plist, use `org-install-letbind' --- lisp/org-taskjuggler.el | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 3c56630..102eabc 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -284,7 +284,10 @@ defined in `org-export-taskjuggler-default-reports'." (message "Exporting...") (setq-default org-done-keywords org-done-keywords) - (let* ((tasks + (let* ((opt-plist (org-combine-plists (org-default-export-plist) + (org-infile-export-plist))) + (org-export-opt-plist opt-plist) + (tasks (org-taskjuggler-resolve-dependencies (org-taskjuggler-assign-task-ids (org-taskjuggler-compute-task-leafiness @@ -335,6 +338,14 @@ defined in `org-export-taskjuggler-default-reports'." (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) + (org-install-letbind) + ;; create local variables for all options, to make sure all called + ;; functions get the correct information + (mapc (lambda (x) + (set (make-local-variable (nth 2 x)) + (plist-get opt-plist (car x)))) + org-export-plist-vars) + (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.3
infer start and end date from SCHEDULED/DEADLINE information * org-taskjuggler.el (org-taskjuggler-date): new function, produce a taskjuggler-compatible date (org-taskjuggler-components): make use of SCHEDULED/DEADLINE properties --- lisp/org-taskjuggler.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 102eabc..7974d1e 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -138,8 +138,6 @@ ;; :END: ;; ;;;; * TODO -;; - Use SCHEDULED and DEADLINE information (not just start and end -;; properties). ;; - Look at org-file-properties, org-global-properties and ;; org-global-properties-fixed ;; - What about property inheritance and org-property-inherit-p? @@ -384,6 +382,10 @@ with the TaskJuggler GUI." (save-excursion (and (org-up-heading-safe) (org-entry-get (point) "ORDERED")))) +(defun org-taskjuggler-date (date) + (let ((time (parse-time-string date))) + (format "%d-%02d-%02d" (nth 5 time) (nth 4 time) (nth 3 time)))) + (defun org-taskjuggler-components () "Return an alist containing all the pertinent information for the current node such as the headline, the level, todo state @@ -395,6 +397,12 @@ information, all the properties, etc." (replace-regexp-in-string "\"" "\\\"" (nth 4 components) t t)) ; quote double quotes in headlines (parent-ordered (org-taskjuggler-parent-is-ordered-p))) + (let ((scheduled (assoc "SCHEDULED" props)) + (deadline (assoc "DEADLINE" props))) + (when scheduled + (push (cons "start" (org-taskjuggler-date (cdr scheduled))) props)) + (when deadline + (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) (push (cons "headline" headline) props) (push (cons "parent-ordered" parent-ordered) props))) -- 1.7.11.3
--- lisp/org-taskjuggler.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7974d1e..f668e7f 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -689,7 +689,8 @@ org-mode priority string." (and (assoc "leaf-node" task) (not (or effort (cdr (assoc "duration" task)) - (cdr (assoc "end" task)) + (and (cdr (assoc "start" task)) + (cdr (assoc "end" task))) (cdr (assoc "period" task))))))) (attributes org-export-taskjuggler-valid-task-attributes)) (insert -- 1.7.11.3
* org-taskjuggler.el (org-export-taskjuggler-default-global-header): new custom variable (org-export-as-taskjuggler): insert global header before anything else --- lisp/org-taskjuggler.el | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index f668e7f..3f829b3 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -221,6 +221,14 @@ with `org-export-taskjuggler-project-tag'" :version "24.1" :type '(repeat (string :tag "Report"))) +(defcustom org-export-taskjuggler-default-global-header + "" + "Default global header for the project. This goes before +project declaration, and might be useful for early macros" + :group 'org-export-taskjuggler + :version "24.1" + :type '(string :tag "Preamble")) + (defcustom org-export-taskjuggler-default-global-properties "shift s40 \"Part time shift\" { workinghours wed, thu, fri off @@ -331,11 +339,6 @@ defined in `org-export-taskjuggler-default-reports'." (setcar tasks (push (cons "version" version) task)))) (with-current-buffer buffer (erase-buffer) - (org-clone-local-variables old-buffer "^org-") - (org-taskjuggler-open-project (car tasks)) - (insert org-export-taskjuggler-default-global-properties) - (insert "\n") - (dolist (resource resources) (org-install-letbind) ;; create local variables for all options, to make sure all called ;; functions get the correct information @@ -344,6 +347,12 @@ defined in `org-export-taskjuggler-default-reports'." (plist-get opt-plist (car x)))) org-export-plist-vars) + (org-clone-local-variables old-buffer "^org-") + (insert org-export-taskjuggler-default-global-header) + (org-taskjuggler-open-project (car tasks)) + (insert org-export-taskjuggler-default-global-properties) + (insert "\n") + (dolist (resource resources) (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.3
* org-taskjuggler.el (org-taskjuggler-open-project): use START - END as an alternative to START +Xd --- lisp/org-taskjuggler.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 3f829b3..92ba79c 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -614,9 +614,11 @@ specified it is calculated (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) (insert - (format "project %s \"%s\" \"%s\" %s +%sd {\n }\n" + (format "project %s \"%s\" \"%s\" %s %s {\n }\n" unique-id headline version start - org-export-taskjuggler-default-project-duration)))) + (or (and end (format "- %s" end)) + (format "+%sd" + org-export-taskjuggler-default-project-duration)))))) (defun org-taskjuggler-filter-and-join (items) "Filter all nil elements from ITEMS and join the remaining ones -- 1.7.11.3
introduce `org-export-taskjuggler-keep-project-as-task' as a flag to toggle the behavior. Keep old behavior as default. * org-taskjuggler.el (org-export-taskjuggler-keep-project-as-task): new custom variable (org-export-as-taskjuggler): optionally drop the topmost "task" (project) (org-taskjuggler-assign-task-ids): adapt path computation by optionally dropping the topmost component (project) --- lisp/org-taskjuggler.el | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 92ba79c..996665d 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -263,6 +263,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-keep-project-as-task t + "Whether to keep the project headline as an umbrella task for + all declared tasks. Setting this to nil will allow maintaining + completely separated task buckets, while still sharing the same + resources pool." + :group 'org-export-taskjuggler + :type 'boolean) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -349,7 +357,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-clone-local-variables old-buffer "^org-") (insert org-export-taskjuggler-default-global-header) - (org-taskjuggler-open-project (car tasks)) + (org-taskjuggler-open-project + (if org-export-taskjuggler-keep-project-as-task + (car tasks) + (pop tasks))) (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) @@ -364,7 +375,9 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe level) (org-taskjuggler-open-task task) (setq org-export-taskjuggler-old-level level))) - (org-taskjuggler-close-maybe 1) + (org-taskjuggler-close-maybe + (if org-export-taskjuggler-keep-project-as-task + 1 2)) (org-taskjuggler-insert-reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") @@ -445,7 +458,11 @@ a path to the current task." (push unique-id (car unique-ids)) (setcar path unique-id))) (push (cons "unique-id" unique-id) task) - (push (cons "path" (mapconcat 'identity (reverse path) ".")) task) + (push (cons "path" + (mapconcat 'identity + (if org-export-taskjuggler-keep-project-as-task + (reverse path) + (cdr (reverse path))) ".")) task) (setq previous-level level) (setq resolved-tasks (append resolved-tasks (list task))))))) -- 1.7.11.3
--- lisp/org-taskjuggler.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 996665d..b08dcdf 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -328,7 +328,7 @@ defined in `org-export-taskjuggler-default-reports'." (unless resources (setq resources `((("resource_id" . ,(user-login-name)) - ("headline" . ,user-full-name) + ("HEADLINE" . ,user-full-name) ("level" . 1))))) ;; add a default allocation to the first task if none was given (unless (assoc "allocate" (car tasks)) @@ -426,7 +426,7 @@ information, all the properties, etc." (when deadline (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) - (push (cons "headline" headline) props) + (push (cons "HEADLINE" headline) props) (push (cons "parent-ordered" parent-ordered) props))) (defun org-taskjuggler-assign-task-ids (tasks) @@ -600,7 +600,7 @@ The id is derived from the headline and made unique against UNIQUE-IDS. If the (downcased) first token of the headline is not unique try to add more (downcased) tokens of the headline or finally add more underscore characters (\"_\")." - (let* ((headline (cdr (assoc "headline" item))) + (let* ((headline (cdr (assoc "HEADLINE" item))) (parts (split-string headline)) (id (org-taskjuggler-clean-id (downcase (pop parts))))) ; try to add more parts of the headline to make it unique @@ -626,7 +626,7 @@ attributes from the PROJECT alist are inserted. If no end date is specified it is calculated `org-export-taskjuggler-default-project-duration' days from now." (let* ((unique-id (cdr (assoc "unique-id" project))) - (headline (cdr (assoc "headline" project))) + (headline (cdr (assoc "HEADLINE" project))) (version (cdr (assoc "version" project))) (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) @@ -677,7 +677,7 @@ is defined it will calculate a unique id for the resource using (or (cdr (assoc "resource_id" resource)) (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) - (headline (cdr (assoc "headline" resource))) + (headline (cdr (assoc "HEADLINE" resource))) (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat @@ -702,7 +702,7 @@ org-mode priority string." (defun org-taskjuggler-open-task (task) (let* ((unique-id (cdr (assoc "unique-id" task))) - (headline (cdr (assoc "headline" task))) + (headline (cdr (assoc "HEADLINE" task))) (effort (org-taskjuggler-clean-effort (cdr (assoc org-effort-property task)))) (depends (cdr (assoc "depends" task))) (allocate (cdr (assoc "allocate" task))) -- 1.7.11.3
This renders reports production much more flexible. * org-taskjuggler.el (org-export-taskjuggler-report-tag): new custom variable (org-export-taskjuggler-valid-report-attributes): new custom variable (org-export-as-taskjuggler): compute reports (org-taskjuggler-open-report): generate report from org item (org-taskjuggler-insert-reports): insert default reports only if no explicit one is defined --- lisp/org-taskjuggler.el | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index b08dcdf..ad1873a 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -181,6 +181,13 @@ resources for the project." :version "24.1" :type 'string) +(defcustom org-export-taskjuggler-report-tag "taskjuggler_report" + "Tag, property or todo used to find the tree containing all the +reports for the project." + :group 'org-export-taskjuggler + :version "24.1" + :type 'string) + (defcustom org-export-taskjuggler-target-version 2.4 "Which version of TaskJuggler the exporter is targeting." :group 'org-export-taskjuggler @@ -263,6 +270,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-valid-report-attributes + '(headline columns definitions timeformat hideresource hidetask + loadunit sorttasks formats) + "Valid attributes for Taskjuggler reports. If one of these + appears as a property for a headline, it will be exported with + the corresponding report." + :group 'org-export-taskjuggler) + (defcustom org-export-taskjuggler-keep-project-as-task t "Whether to keep the project headline as an umbrella task for all declared tasks. Setting this to nil will allow maintaining @@ -313,6 +328,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-map-entries 'org-taskjuggler-components org-export-taskjuggler-resource-tag nil 'archive 'comment))) + (reports + (org-map-entries + 'org-taskjuggler-components + org-export-taskjuggler-report-tag nil 'archive 'comment)) (filename (expand-file-name (concat (file-name-sans-extension @@ -378,7 +397,7 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe (if org-export-taskjuggler-keep-project-as-task 1 2)) - (org-taskjuggler-insert-reports) + (org-taskjuggler-insert-reports reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") (message "Exporting... done")) @@ -739,6 +758,16 @@ org-mode priority string." (org-taskjuggler-get-attributes task attributes) "\n")))) +(defun org-taskjuggler-open-report (report) + (let* ((kind (or (cdr (assoc "report-kind" report)) "taskreport")) + (headline (cdr (assoc "HEADLINE" report))) + (attributes org-export-taskjuggler-valid-report-attributes)) + (insert + (concat + kind " \"" headline "\" {\n" + (org-taskjuggler-get-attributes report attributes) + "\n}\n")))) + (defun org-taskjuggler-close-maybe (level) (while (> org-export-taskjuggler-old-level level) (insert "}\n") @@ -746,10 +775,13 @@ org-mode priority string." (when (= org-export-taskjuggler-old-level level) (insert "}\n"))) -(defun org-taskjuggler-insert-reports () - (let (report) - (dolist (report org-export-taskjuggler-default-reports) - (insert report "\n")))) +(defun org-taskjuggler-insert-reports (reports) + (if reports + (dolist (report (cdr reports)) + (org-taskjuggler-open-report report)) + (let (report) + (dolist (report org-export-taskjuggler-default-reports) + (insert report "\n"))))) (provide 'org-taskjuggler) -- 1.7.11.3
--- doc/org.texi | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 8613793..53e001b 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -11882,9 +11882,9 @@ nodes of a document or strictly follow the order of the nodes in the document. Instead the TaskJuggler exporter looks for a tree that defines the tasks and -a optionally tree that defines the resources for this project. It then -creates a TaskJuggler file based on these trees and the attributes defined in -all the nodes. +optionally trees that define the resources and reports for this project. +It then creates a TaskJuggler file based on these trees and the attributes +defined in all the nodes. @subsection TaskJuggler export commands @@ -11893,7 +11893,8 @@ all the nodes. Export as a TaskJuggler file. @orgcmd{C-c C-e J,org-export-as-taskjuggler-and-open} -Export as a TaskJuggler file and then open the file with TaskJugglerUI. +Export as a TaskJuggler file and then open the file with TaskJugglerUI (only +for TaskJugglerUI 2.x). @end table @subsection Tasks @@ -11931,15 +11932,17 @@ time. @subsection Export of properties -The exporter also takes TODO state information into consideration, i.e.@: if a -task is marked as done it will have the corresponding attribute in -TaskJuggler (@samp{complete 100}). Also it will export any property on a task -resource or resource node which is known to TaskJuggler, such as -@samp{limits}, @samp{vacation}, @samp{shift}, @samp{booking}, -@samp{efficiency}, @samp{journalentry}, @samp{rate} for resources or -@samp{account}, @samp{start}, @samp{note}, @samp{duration}, @samp{end}, -@samp{journalentry}, @samp{milestone}, @samp{reference}, @samp{responsible}, -@samp{scheduling}, etc for tasks. +The exporter also takes TODO state information into consideration, i.e.@: if +a task is marked as done it will have the corresponding attribute in +TaskJuggler (@samp{complete 100}). Scheduling information is also taken into +account to set start/end dates for tasks. + +The exporter will also export any property on a task resource or resource +node which is known to TaskJuggler, such as @samp{limits}, @samp{vacation}, +@samp{shift}, @samp{booking}, @samp{efficiency}, @samp{journalentry}, +@samp{rate} for resources or @samp{account}, @samp{start}, @samp{note}, +@samp{duration}, @samp{end}, @samp{journalentry}, @samp{milestone}, +@samp{reference}, @samp{responsible}, @samp{scheduling}, etc for tasks. @subsection Dependencies @@ -11985,11 +11988,20 @@ examples should illustrate this: @vindex org-export-taskjuggler-default-reports TaskJuggler can produce many kinds of reports (e.g.@: gantt chart, resource allocation, etc). The user defines what kind of reports should be generated -for a project in the TaskJuggler file. The exporter will automatically insert -some default reports in the file. These defaults are defined in -@code{org-export-taskjuggler-default-reports}. They can be modified using -customize along with a number of other options. For a more complete list, see -@kbd{M-x customize-group @key{RET} org-export-taskjuggler @key{RET}}. +for a project in the TaskJuggler file. By default, the exporter will +automatically insert some pre-set reports in the file. These defaults are +defined in @code{org-export-taskjuggler-default-reports}. They can be +modified using customize along with a number of other options. For a more +complete list, see @kbd{M-x customize-group @key{RET} org-export-taskjuggler +@key{RET}}. + +Alternately, the user can tag a tree with +@code{org-export-taskjuggler-report-tag}, and define reports in sub-nodes, +similarly to what is done with tasks or resources. The properties used for +report generation are defined in +@code{org-export-taskjuggler-valid-report-attributes}. In addition, a special +property named @samp{report-kind} is used to define the kind of report one +wants to generate (by default, a @samp{taskreport}). For more information and examples see the Org-taskjuggler tutorial at @uref{http://orgmode.org/worg/org-tutorials/org-taskjuggler.html}. -- 1.7.11.3
Hi Yann, Yann Hodique <yann.hodique@gmail.com> writes: > Here are a couple of patches for org-taskjuggler.el thanks for this. I've quickly check by just reading the patches, and this looks good. I copy Christian, hoping he will have time to double-check. Did you sign the FSF papers? If you didn't, please fill in this form and send it to assign@fsf.org: http://orgmode.org/w/?p=org-mode.git;a=blob_plain;f=request-assign-future.txt;hb=HEAD Also, please reread http://orgmode.org/worg/org-contribute.html#sec-5 to format the commit messages more appropriately. Thanks, -- Bastien
>>>>> "Bastien" == Bastien <bzg@gnu.org> writes: > Hi Yann, > Yann Hodique <yann.hodique@gmail.com> writes: >> Here are a couple of patches for org-taskjuggler.el > thanks for this. I've quickly check by just reading the patches, > and this looks good. I copy Christian, hoping he will have time > to double-check. > Did you sign the FSF papers? Hi Bastien, Thanks for the quick feedback. I did sign FSF papers a few years ago, but not sure Emacs was explicitly in the scope. Anyway, I just sent another form to be sure. > Also, please reread http://orgmode.org/worg/org-contribute.html#sec-5 > to format the commit messages more appropriately. Ok. I'll wait a bit for potential feedback from Christian and rework the messages. Thanks, Yann. -- The surest way to keep a secret is to make people believe they already know the answer. -- Ancient Fremen Wisdom
CC'ing Christian again with a working email address this time.
Bastien <bzg@gnu.org> writes:
> thanks for this. I've quickly check by just reading the patches,
> and this looks good. I copy Christian, hoping he will have time
> to double-check.
--
Bastien
Hi Yann
Yann Hodique <yann.hodique@gmail.com> writes:
> Here are a couple of patches for org-taskjuggler.el
>
> My main goals with these were to:
>
> - be able to leverage SCHEDULE/DEADLINE information, so as to be able
> to leverage org timelines in complement to the reports
>
> - be able to #+BIND some of the exporter variables (such as the
> preamble)
>
> - be able to define reports in the org file itself, without having to
> mess with a custom variable
>
> Any feedback is highly welcome.
I have looked at your patches. I have not had time to try them but
reading the diffs it looks excellent. They implement some features which
make the exporter much more flexible.
I have one comment to patch "make project umbrella task optional" which
I'll adress separately.
Thanks
Christian
--
Christian Egli
Swiss Library for the Blind, Visually Impaired and Print Disabled
Grubenstrasse 12, CH-8045 Zürich, Switzerland
Yann Hodique <yann.hodique@gmail.com> writes:
> +(defcustom org-export-taskjuggler-keep-project-as-task t
> + "Whether to keep the project headline as an umbrella task for
> + all declared tasks. Setting this to nil will allow maintaining
> + completely separated task buckets, while still sharing the same
> + resources pool."
I'm trying to understand the use case here. If I understand correctly
the container headline will no longer unconditionally generate a root
task. So you could have multiple root tasks? Does this work in both
versions of tj?
Thanks
Christian
--
Christian Egli
Swiss Library for the Blind, Visually Impaired and Print Disabled
Grubenstrasse 12, CH-8045 Zürich, Switzerland
>>>>> "Christian" == Christian Egli <christian.egli@sbs.ch> writes: > Yann Hodique <yann.hodique@gmail.com> writes: >> +(defcustom org-export-taskjuggler-keep-project-as-task t >> + "Whether to keep the project headline as an umbrella task for >> + all declared tasks. Setting this to nil will allow maintaining >> + completely separated task buckets, while still sharing the same >> + resources pool." > I'm trying to understand the use case here. If I understand correctly > the container headline will no longer unconditionally generate a root > task. So you could have multiple root tasks? Does this work in both > versions of tj? Yes, basically the use case is the following. From an org code like: --8<---------------cut here---------------start------------->8--- * Main :taskjuggler_project: ** Task1 ** Task2 --8<---------------cut here---------------end--------------->8--- the default behavior is to generate something like --8<---------------cut here---------------start------------->8--- project main Main (} task main "Main" { task task1 "Task1" {} task task2 "Task2" {} } --8<---------------cut here---------------end--------------->8--- leading to a report like --8<---------------cut here---------------start------------->8--- 1. Main 1.1 Task1 1.2 Taks2 --8<---------------cut here---------------end--------------->8--- while the new (non-default) one would generate --8<---------------cut here---------------start------------->8--- project main Main {} task task1 "Task1" {} task task2 "Task2" {} --8<---------------cut here---------------end--------------->8--- leading to a report like --8<---------------cut here---------------start------------->8--- 1 Task1 2 Task2 --8<---------------cut here---------------end--------------->8--- I must confess this is mostly a way to avoid questions from people looking at the report, asking why my task numbers are all 1.x :) AFAICT it seems to work fine with either tj2 or tj3. I'm using tj3 only myself, but the UI of tj2 doesn't complain at all about those multiple root tasks. Thanks, Yann -- When faced with necessary actions, there are always choices. So long as the job gets done. -- COUNT HASIMIR FENRING, Dispatches from Arrakis
On 08/12/2012 10:03 AM, Yann Hodique wrote: >>>>>> "Christian" == Christian Egli<christian.egli@sbs.ch> writes: ... > while the new (non-default) one would generate > --8<---------------cut here---------------start------------->8--- > project main Main {} > task task1 "Task1" {} > task task2 "Task2" {} > --8<---------------cut here---------------end--------------->8--- > > leading to a report like > --8<---------------cut here---------------start------------->8--- > 1 Task1 > 2 Task2 > --8<---------------cut here---------------end--------------->8--- > > I must confess this is mostly a way to avoid questions from people > looking at the report, asking why my task numbers are all 1.x :) Yeah that sucks. If there would be a way to make the numbers configurable in org that'd be even better. I am responsible for parts of a project, so there is an externally defined numbering in some cases. Bit I might go at this myself if your patches land, which look excellent BTW. Cheers, Simon > > AFAICT it seems to work fine with either tj2 or tj3. I'm using tj3 only > myself, but the UI of tj2 doesn't complain at all about those multiple > root tasks. > > Thanks, > > Yann >
Simon Thum <simon.thum@gmx.de> writes:
> Bit I might go at this myself if your patches land, which look excellent
> BTW.
The patches will land as soon as we the copyright assignment is
processed. Chances are that this will be after Org 7.9 though,
but equal chances are that 7.9.1 will closely follow 7.9, so please
go ahead and hack. :)
--
Bastien
Yann Hodique <yann.hodique@gmail.com> writes: >>>>>> "Christian" == Christian Egli <christian.egli@sbs.ch> writes: >> I'm trying to understand the use case here. If I understand correctly >> the container headline will no longer unconditionally generate a root >> task. So you could have multiple root tasks? Does this work in both >> versions of tj? > > Yes, basically the use case is the following. [snip] > AFAICT it seems to work fine with either tj2 or tj3. OK this clears it up. So basically all the patches are fine from my pov. Thanks again. Christian -- Christian Egli Swiss Library for the Blind, Visually Impaired and Print Disabled Grubenstrasse 12, CH-8045 Zürich, Switzerland
Hi Christian,
Christian Egli <christian.egli@sbs.ch> writes:
> OK this clears it up. So basically all the patches are fine from my pov.
> Thanks again.
Thanks for confirming.
I'll commit the patches when the FSF papers arrive.
Best,
--
Bastien
Hi, here is a new version of the patch series. Changes are: - fixed commit messages format - added a few missing attributes in `org-export-taskjuggler-valid-resource-attributes' (1/11) and `org-export-taskjuggler-valid-report-attributes' (9/11) - added another milestone-related fix: attribute "length" prevents milestone creation (same as "duration"). Fix merged into 4/11 - added another patch (11/11) to make org-publish taskjuggler-capable. Feel free to reject this one if it's deemed undesirable. Thanks, Yann. Yann Hodique (11): org-taskjuggler: make task and resource properties customizable org-taskjuggler: properly install local variables at export time org-taskjuggler: make use of org properties org-taskjuggler: fix milestone definition org-taskjuggler: introduce a global header, for early macros org-taskjuggler: use project end date, if specified org-taskjuggler: make project umbrella task optional org-taskjuggler: disambiguate "headline", as it's also a valid property org-taskjuggler: allow reports definition from within the org file org-taskjuggler: update doc to reflect latest changes org-taskjuggler: make taskjuggler compatible with org-publish doc/org.texi | 48 ++++++++----- lisp/org-publish.el | 6 ++ lisp/org-taskjuggler.el | 180 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 180 insertions(+), 54 deletions(-) -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-valid-task-attributes): new custom variable (org-export-taskjuggler-valid-resource-attributes): new custom variable --- lisp/org-taskjuggler.el | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index aa645d2..7d9d203 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -240,6 +240,24 @@ but before any resource and task declarations." :version "24.1" :type '(string :tag "Preamble")) +(defcustom org-export-taskjuggler-valid-task-attributes + '(account start note duration endbuffer endcredit end + flags journalentry length limits maxend maxstart minend + minstart period reference responsible scheduling + startbuffer startcredit statusnote) + "Valid attributes for Taskjuggler tasks. If one of these + appears as a property for a headline, it will be exported with + the corresponding task." + :group 'org-export-taskjuggler) + +(defcustom org-export-taskjuggler-valid-resource-attributes + '(limits vacation shift booking efficiency journalentry rate + workinghours flags) + "Valid attributes for Taskjuggler resources. If one of these + appears as a property for a headline, it will be exported with + the corresponding resource." + :group 'org-export-taskjuggler) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -614,7 +632,7 @@ is defined it will calculate a unique id for the resource using (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) (headline (cdr (assoc "headline" resource))) - (attributes '(limits vacation shift booking efficiency journalentry rate))) + (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat "resource " id " \"" headline "\" {\n " @@ -655,11 +673,7 @@ org-mode priority string." (cdr (assoc "duration" task)) (cdr (assoc "end" task)) (cdr (assoc "period" task))))))) - (attributes - '(account start note duration endbuffer endcredit end - flags journalentry length maxend maxstart minend - minstart period reference responsible scheduling - startbuffer startcredit statusnote))) + (attributes org-export-taskjuggler-valid-task-attributes)) (insert (concat "task " unique-id " \"" headline "\" {\n" -- 1.7.11.4
* org-taskjuggler.el (org-export-as-taskjuggler): compute opt-plist, use `org-install-letbind' --- lisp/org-taskjuggler.el | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7d9d203..529cda0 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -285,7 +285,10 @@ defined in `org-export-taskjuggler-default-reports'." (message "Exporting...") (setq-default org-done-keywords org-done-keywords) - (let* ((tasks + (let* ((opt-plist (org-combine-plists (org-default-export-plist) + (org-infile-export-plist))) + (org-export-opt-plist opt-plist) + (tasks (org-taskjuggler-resolve-dependencies (org-taskjuggler-assign-task-ids (org-taskjuggler-compute-task-leafiness @@ -336,6 +339,14 @@ defined in `org-export-taskjuggler-default-reports'." (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) + (org-install-letbind) + ;; create local variables for all options, to make sure all called + ;; functions get the correct information + (mapc (lambda (x) + (set (make-local-variable (nth 2 x)) + (plist-get opt-plist (car x)))) + org-export-plist-vars) + (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-date): new function, produce a taskjuggler-compatible date (org-taskjuggler-components): make use of SCHEDULED/DEADLINE properties infer start and end date from SCHEDULED/DEADLINE information --- lisp/org-taskjuggler.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 529cda0..93f0cc7 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -138,8 +138,6 @@ ;; :END: ;; ;;;; * TODO -;; - Use SCHEDULED and DEADLINE information (not just start and end -;; properties). ;; - Look at org-file-properties, org-global-properties and ;; org-global-properties-fixed ;; - What about property inheritance and org-property-inherit-p? @@ -385,6 +383,10 @@ with the TaskJuggler GUI." (save-excursion (and (org-up-heading-safe) (org-entry-get (point) "ORDERED")))) +(defun org-taskjuggler-date (date) + (let ((time (parse-time-string date))) + (format "%d-%02d-%02d" (nth 5 time) (nth 4 time) (nth 3 time)))) + (defun org-taskjuggler-components () "Return an alist containing all the pertinent information for the current node such as the headline, the level, todo state @@ -396,6 +398,12 @@ information, all the properties, etc." (replace-regexp-in-string "\"" "\\\"" (nth 4 components) t t)) ; quote double quotes in headlines (parent-ordered (org-taskjuggler-parent-is-ordered-p))) + (let ((scheduled (assoc "SCHEDULED" props)) + (deadline (assoc "DEADLINE" props))) + (when scheduled + (push (cons "start" (org-taskjuggler-date (cdr scheduled))) props)) + (when deadline + (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) (push (cons "headline" headline) props) (push (cons "parent-ordered" parent-ordered) props))) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-open-task): task with end-only is also a milestone (deadline), task with length is not --- lisp/org-taskjuggler.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 93f0cc7..a18cdf8 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -689,8 +689,10 @@ org-mode priority string." (milestone (or (cdr (assoc "milestone" task)) (and (assoc "leaf-node" task) (not (or effort + (cdr (assoc "length" task)) (cdr (assoc "duration" task)) - (cdr (assoc "end" task)) + (and (cdr (assoc "start" task)) + (cdr (assoc "end" task))) (cdr (assoc "period" task))))))) (attributes org-export-taskjuggler-valid-task-attributes)) (insert -- 1.7.11.4
--- lisp/org-taskjuggler.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7974d1e..f668e7f 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -689,7 +689,8 @@ org-mode priority string." (and (assoc "leaf-node" task) (not (or effort (cdr (assoc "duration" task)) - (cdr (assoc "end" task)) + (and (cdr (assoc "start" task)) + (cdr (assoc "end" task))) (cdr (assoc "period" task))))))) (attributes org-export-taskjuggler-valid-task-attributes)) (insert -- 1.7.11.3
* org-taskjuggler.el (org-export-taskjuggler-default-global-header): new custom variable (org-export-as-taskjuggler): insert global header before anything else --- lisp/org-taskjuggler.el | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index a18cdf8..c997da7 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -221,6 +221,14 @@ with `org-export-taskjuggler-project-tag'" :version "24.1" :type '(repeat (string :tag "Report"))) +(defcustom org-export-taskjuggler-default-global-header + "" + "Default global header for the project. This goes before +project declaration, and might be useful for early macros" + :group 'org-export-taskjuggler + :version "24.1" + :type '(string :tag "Preamble")) + (defcustom org-export-taskjuggler-default-global-properties "shift s40 \"Part time shift\" { workinghours wed, thu, fri off @@ -332,11 +340,6 @@ defined in `org-export-taskjuggler-default-reports'." (setcar tasks (push (cons "version" version) task)))) (with-current-buffer buffer (erase-buffer) - (org-clone-local-variables old-buffer "^org-") - (org-taskjuggler-open-project (car tasks)) - (insert org-export-taskjuggler-default-global-properties) - (insert "\n") - (dolist (resource resources) (org-install-letbind) ;; create local variables for all options, to make sure all called ;; functions get the correct information @@ -345,6 +348,12 @@ defined in `org-export-taskjuggler-default-reports'." (plist-get opt-plist (car x)))) org-export-plist-vars) + (org-clone-local-variables old-buffer "^org-") + (insert org-export-taskjuggler-default-global-header) + (org-taskjuggler-open-project (car tasks)) + (insert org-export-taskjuggler-default-global-properties) + (insert "\n") + (dolist (resource resources) (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-open-project): use START - END as an alternative to START +Xd --- lisp/org-taskjuggler.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index c997da7..7376302 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -615,9 +615,11 @@ specified it is calculated (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) (insert - (format "project %s \"%s\" \"%s\" %s +%sd {\n }\n" + (format "project %s \"%s\" \"%s\" %s %s {\n }\n" unique-id headline version start - org-export-taskjuggler-default-project-duration)))) + (or (and end (format "- %s" end)) + (format "+%sd" + org-export-taskjuggler-default-project-duration)))))) (defun org-taskjuggler-filter-and-join (items) "Filter all nil elements from ITEMS and join the remaining ones -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-keep-project-as-task): new custom variable (org-export-as-taskjuggler): optionally drop the topmost "task" (project) (org-taskjuggler-assign-task-ids): adapt path computation by optionally dropping the topmost component (project) introduce `org-export-taskjuggler-keep-project-as-task' as a flag to toggle the behavior. Keep old behavior as default. --- lisp/org-taskjuggler.el | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7376302..3c97e03 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -264,6 +264,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-keep-project-as-task t + "Whether to keep the project headline as an umbrella task for + all declared tasks. Setting this to nil will allow maintaining + completely separated task buckets, while still sharing the same + resources pool." + :group 'org-export-taskjuggler + :type 'boolean) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -350,7 +358,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-clone-local-variables old-buffer "^org-") (insert org-export-taskjuggler-default-global-header) - (org-taskjuggler-open-project (car tasks)) + (org-taskjuggler-open-project + (if org-export-taskjuggler-keep-project-as-task + (car tasks) + (pop tasks))) (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) @@ -365,7 +376,9 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe level) (org-taskjuggler-open-task task) (setq org-export-taskjuggler-old-level level))) - (org-taskjuggler-close-maybe 1) + (org-taskjuggler-close-maybe + (if org-export-taskjuggler-keep-project-as-task + 1 2)) (org-taskjuggler-insert-reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") @@ -446,7 +459,11 @@ a path to the current task." (push unique-id (car unique-ids)) (setcar path unique-id))) (push (cons "unique-id" unique-id) task) - (push (cons "path" (mapconcat 'identity (reverse path) ".")) task) + (push (cons "path" + (mapconcat 'identity + (if org-export-taskjuggler-keep-project-as-task + (reverse path) + (cdr (reverse path))) ".")) task) (setq previous-level level) (setq resolved-tasks (append resolved-tasks (list task))))))) -- 1.7.11.4
--- lisp/org-taskjuggler.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 3c97e03..33b111d 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -329,7 +329,7 @@ defined in `org-export-taskjuggler-default-reports'." (unless resources (setq resources `((("resource_id" . ,(user-login-name)) - ("headline" . ,user-full-name) + ("HEADLINE" . ,user-full-name) ("level" . 1))))) ;; add a default allocation to the first task if none was given (unless (assoc "allocate" (car tasks)) @@ -427,7 +427,7 @@ information, all the properties, etc." (when deadline (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) - (push (cons "headline" headline) props) + (push (cons "HEADLINE" headline) props) (push (cons "parent-ordered" parent-ordered) props))) (defun org-taskjuggler-assign-task-ids (tasks) @@ -601,7 +601,7 @@ The id is derived from the headline and made unique against UNIQUE-IDS. If the (downcased) first token of the headline is not unique try to add more (downcased) tokens of the headline or finally add more underscore characters (\"_\")." - (let* ((headline (cdr (assoc "headline" item))) + (let* ((headline (cdr (assoc "HEADLINE" item))) (parts (split-string headline)) (id (org-taskjuggler-clean-id (downcase (pop parts))))) ; try to add more parts of the headline to make it unique @@ -627,7 +627,7 @@ attributes from the PROJECT alist are inserted. If no end date is specified it is calculated `org-export-taskjuggler-default-project-duration' days from now." (let* ((unique-id (cdr (assoc "unique-id" project))) - (headline (cdr (assoc "headline" project))) + (headline (cdr (assoc "HEADLINE" project))) (version (cdr (assoc "version" project))) (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) @@ -678,7 +678,7 @@ is defined it will calculate a unique id for the resource using (or (cdr (assoc "resource_id" resource)) (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) - (headline (cdr (assoc "headline" resource))) + (headline (cdr (assoc "HEADLINE" resource))) (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat @@ -703,7 +703,7 @@ org-mode priority string." (defun org-taskjuggler-open-task (task) (let* ((unique-id (cdr (assoc "unique-id" task))) - (headline (cdr (assoc "headline" task))) + (headline (cdr (assoc "HEADLINE" task))) (effort (org-taskjuggler-clean-effort (cdr (assoc org-effort-property task)))) (depends (cdr (assoc "depends" task))) (allocate (cdr (assoc "allocate" task))) -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-report-tag): new custom variable (org-export-taskjuggler-valid-report-attributes): new custom variable (org-export-as-taskjuggler): compute reports (org-taskjuggler-open-report): generate report from org item (org-taskjuggler-insert-reports): insert default reports only if no explicit one is defined --- lisp/org-taskjuggler.el | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 33b111d..49c24ff 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -181,6 +181,13 @@ resources for the project." :version "24.1" :type 'string) +(defcustom org-export-taskjuggler-report-tag "taskjuggler_report" + "Tag, property or todo used to find the tree containing all the +reports for the project." + :group 'org-export-taskjuggler + :version "24.1" + :type 'string) + (defcustom org-export-taskjuggler-target-version 2.4 "Which version of TaskJuggler the exporter is targeting." :group 'org-export-taskjuggler @@ -264,6 +271,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-valid-report-attributes + '(headline columns definitions timeformat hideresource hidetask + loadunit sorttasks formats period) + "Valid attributes for Taskjuggler reports. If one of these + appears as a property for a headline, it will be exported with + the corresponding report." + :group 'org-export-taskjuggler) + (defcustom org-export-taskjuggler-keep-project-as-task t "Whether to keep the project headline as an umbrella task for all declared tasks. Setting this to nil will allow maintaining @@ -314,6 +329,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-map-entries 'org-taskjuggler-components org-export-taskjuggler-resource-tag nil 'archive 'comment))) + (reports + (org-map-entries + 'org-taskjuggler-components + org-export-taskjuggler-report-tag nil 'archive 'comment)) (filename (expand-file-name (concat (file-name-sans-extension @@ -379,7 +398,7 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe (if org-export-taskjuggler-keep-project-as-task 1 2)) - (org-taskjuggler-insert-reports) + (org-taskjuggler-insert-reports reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") (message "Exporting... done")) @@ -741,6 +760,16 @@ org-mode priority string." (org-taskjuggler-get-attributes task attributes) "\n")))) +(defun org-taskjuggler-open-report (report) + (let* ((kind (or (cdr (assoc "report-kind" report)) "taskreport")) + (headline (cdr (assoc "HEADLINE" report))) + (attributes org-export-taskjuggler-valid-report-attributes)) + (insert + (concat + kind " \"" headline "\" {\n" + (org-taskjuggler-get-attributes report attributes) + "\n}\n")))) + (defun org-taskjuggler-close-maybe (level) (while (> org-export-taskjuggler-old-level level) (insert "}\n") @@ -748,10 +777,13 @@ org-mode priority string." (when (= org-export-taskjuggler-old-level level) (insert "}\n"))) -(defun org-taskjuggler-insert-reports () - (let (report) - (dolist (report org-export-taskjuggler-default-reports) - (insert report "\n")))) +(defun org-taskjuggler-insert-reports (reports) + (if reports + (dolist (report (cdr reports)) + (org-taskjuggler-open-report report)) + (let (report) + (dolist (report org-export-taskjuggler-default-reports) + (insert report "\n"))))) (provide 'org-taskjuggler) -- 1.7.11.4
--- doc/org.texi | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 3fdb4ac..0f8b0d9 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -11898,9 +11898,9 @@ nodes of a document or strictly follow the order of the nodes in the document. Instead the TaskJuggler exporter looks for a tree that defines the tasks and -a optionally tree that defines the resources for this project. It then -creates a TaskJuggler file based on these trees and the attributes defined in -all the nodes. +optionally trees that define the resources and reports for this project. +It then creates a TaskJuggler file based on these trees and the attributes +defined in all the nodes. @subsection TaskJuggler export commands @@ -11909,7 +11909,8 @@ all the nodes. Export as a TaskJuggler file. @orgcmd{C-c C-e J,org-export-as-taskjuggler-and-open} -Export as a TaskJuggler file and then open the file with TaskJugglerUI. +Export as a TaskJuggler file and then open the file with TaskJugglerUI (only +for TaskJugglerUI 2.x). @end table @subsection Tasks @@ -11947,15 +11948,17 @@ time. @subsection Export of properties -The exporter also takes TODO state information into consideration, i.e.@: if a -task is marked as done it will have the corresponding attribute in -TaskJuggler (@samp{complete 100}). Also it will export any property on a task -resource or resource node which is known to TaskJuggler, such as -@samp{limits}, @samp{vacation}, @samp{shift}, @samp{booking}, -@samp{efficiency}, @samp{journalentry}, @samp{rate} for resources or -@samp{account}, @samp{start}, @samp{note}, @samp{duration}, @samp{end}, -@samp{journalentry}, @samp{milestone}, @samp{reference}, @samp{responsible}, -@samp{scheduling}, etc for tasks. +The exporter also takes TODO state information into consideration, i.e.@: if +a task is marked as done it will have the corresponding attribute in +TaskJuggler (@samp{complete 100}). Scheduling information is also taken into +account to set start/end dates for tasks. + +The exporter will also export any property on a task resource or resource +node which is known to TaskJuggler, such as @samp{limits}, @samp{vacation}, +@samp{shift}, @samp{booking}, @samp{efficiency}, @samp{journalentry}, +@samp{rate} for resources or @samp{account}, @samp{start}, @samp{note}, +@samp{duration}, @samp{end}, @samp{journalentry}, @samp{milestone}, +@samp{reference}, @samp{responsible}, @samp{scheduling}, etc for tasks. @subsection Dependencies @@ -12001,11 +12004,20 @@ examples should illustrate this: @vindex org-export-taskjuggler-default-reports TaskJuggler can produce many kinds of reports (e.g.@: gantt chart, resource allocation, etc). The user defines what kind of reports should be generated -for a project in the TaskJuggler file. The exporter will automatically insert -some default reports in the file. These defaults are defined in -@code{org-export-taskjuggler-default-reports}. They can be modified using -customize along with a number of other options. For a more complete list, see -@kbd{M-x customize-group @key{RET} org-export-taskjuggler @key{RET}}. +for a project in the TaskJuggler file. By default, the exporter will +automatically insert some pre-set reports in the file. These defaults are +defined in @code{org-export-taskjuggler-default-reports}. They can be +modified using customize along with a number of other options. For a more +complete list, see @kbd{M-x customize-group @key{RET} org-export-taskjuggler +@key{RET}}. + +Alternately, the user can tag a tree with +@code{org-export-taskjuggler-report-tag}, and define reports in sub-nodes, +similarly to what is done with tasks or resources. The properties used for +report generation are defined in +@code{org-export-taskjuggler-valid-report-attributes}. In addition, a special +property named @samp{report-kind} is used to define the kind of report one +wants to generate (by default, a @samp{taskreport}). For more information and examples see the Org-taskjuggler tutorial at @uref{http://orgmode.org/worg/org-tutorials/org-taskjuggler.html}. -- 1.7.11.4
* lisp/org-publish.el (org-publish-org-to-taskjuggler): new function to publish taskjuggler projects * lisp/org-taskjuggler.el (org-export-as-taskjuggler): adapt signature to reflect standard interface, in particular allow export to buffer --- lisp/org-publish.el | 6 ++++++ lisp/org-taskjuggler.el | 33 +++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lisp/org-publish.el b/lisp/org-publish.el index ed2db3a..e78e2d4 100644 --- a/lisp/org-publish.el +++ b/lisp/org-publish.el @@ -649,6 +649,12 @@ See `org-publish-org-to' to the list of arguments." (org-publish-with-aux-preprocess-maybe (org-publish-org-to "utf8" plist filename pub-dir))) +(defun org-publish-org-to-taskjuggler (plist filename pub-dir) + "Publish an org file to TaskJuggler. +See `org-publish-org-to' to the list of arguments." + (org-publish-with-aux-preprocess-maybe + (org-publish-org-to "taskjuggler" plist filename pub-dir))) + (defun org-publish-attachment (plist filename pub-dir) "Publish a file with no transformation of any kind. See `org-publish-org-to' to the list of arguments." diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 49c24ff..1733fe8 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -298,7 +298,8 @@ but before any resource and task declarations." (defvar org-export-taskjuggler-old-level) ;;;###autoload -(defun org-export-as-taskjuggler () +(defun org-export-as-taskjuggler (&optional arg hidden ext-plist + to-buffer body-only pub-dir) "Export parts of the current buffer as a TaskJuggler file. The exporter looks for a tree with tag, property or todo that matches `org-export-taskjuggler-project-tag' and takes this as @@ -310,11 +311,12 @@ resources for the project. If no resources are specified, a default resource is created and allocated to the project. Also the taskjuggler project will be created with default reports as defined in `org-export-taskjuggler-default-reports'." - (interactive) + (interactive "P") (message "Exporting...") (setq-default org-done-keywords org-done-keywords) (let* ((opt-plist (org-combine-plists (org-default-export-plist) + ext-plist (org-infile-export-plist))) (org-export-opt-plist opt-plist) (tasks @@ -333,12 +335,20 @@ defined in `org-export-taskjuggler-default-reports'." (org-map-entries 'org-taskjuggler-components org-export-taskjuggler-report-tag nil 'archive 'comment)) - (filename (expand-file-name - (concat - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)) - org-export-taskjuggler-extension))) - (buffer (find-file-noselect filename)) + (filename (if to-buffer + nil + (concat (file-name-as-directory + (or pub-dir + (org-export-directory :tj opt-plist))) + (file-name-sans-extension + (file-name-nondirectory buffer-file-name)) + org-export-taskjuggler-extension))) + (buffer (if to-buffer + (cond + ((eq to-buffer 'string) + (get-buffer-create "*Org Taskjuggler Export*")) + (t (get-buffer-create to-buffer))) + (find-file-noselect filename))) (old-buffer (current-buffer)) (org-export-taskjuggler-old-level 0) task resource) @@ -399,10 +409,13 @@ defined in `org-export-taskjuggler-default-reports'." (if org-export-taskjuggler-keep-project-as-task 1 2)) (org-taskjuggler-insert-reports reports) - (save-buffer) + (or to-buffer (save-buffer)) (or (org-export-push-to-kill-ring "TaskJuggler") (message "Exporting... done")) - (current-buffer)))) + (if (eq to-buffer 'string) + (prog1 (buffer-substring (point-min) (point-max)) + (kill-buffer (current-buffer))) + (current-buffer))))) ;;;###autoload (defun org-export-as-taskjuggler-and-open () -- 1.7.11.4
Hi Yann, Yann Hodique <yann.hodique@gmail.com> writes: > here is a new version of the patch series. Thanks. > Changes are: > > - fixed commit messages format Thanks for this effort -- not nitpicking, but there is room left for small improvements. - The summary line should be "org-taskjuggler.el: Sentence" (note the .el after "org-taskjuggler"). - The ChangeLog entries should be sentences, starting with an uppercase letter and ending with a full stop. - It should be filled with C-x f 72 (or 70) then M-q. - "Interactive functions" = "commands" "custom variables" = "options" This makes the entries shorter and tells immediatly what it is about. All this because those entries are later on automatically parsed to get added to Emacs. I review them manually, but fixing lots of entries manually take a lot of time. I'm having a branch with your changes -- I'll apply it when you confirm you received the FSF papers. Thanks! -- Bastien
>>>>> "Bastien" == Bastien <bzg@altern.org> writes: > Thanks for this effort -- not nitpicking, but there is room left for > small improvements. Sure, no problem. I will do that right away. Actually the last series was a bit messy anyway, with my old 4/10 showing up again (which brought confusion to patchwork). Thanks, Yann. -- "There is no escape--we pay for the violence of our ancestors. " -- from "The Collected Sayings of Muad'Dib" by the Princess Irulan
Hi, here is a new version of the patch series. Changes are: - fixed commit messages format Yann Hodique (11): org-taskjuggler.el: Make task and resource properties customizable org-taskjuggler.el: Properly install local variables at export time org-taskjuggler.el: Make use of org properties org-taskjuggler.el: Fix milestone definition org-taskjuggler.el: Introduce a global header, for early macros org-taskjuggler.el: Use project end date, if specified org-taskjuggler.el: Make project umbrella task optional org-taskjuggler.el: Disambiguate "headline", as it's a valid attribute org-taskjuggler.el: Allow reports definition from within the org file org-taskjuggler.el: Update doc to reflect latest changes org-taskjuggler.el: Make taskjuggler compatible with org-publish doc/org.texi | 48 ++++++++----- lisp/org-publish.el | 6 ++ lisp/org-taskjuggler.el | 180 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 180 insertions(+), 54 deletions(-) -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-valid-task-attributes): Add new option. (org-export-taskjuggler-valid-resource-attributes): Add new custom option. --- lisp/org-taskjuggler.el | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index aa645d2..7d9d203 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -240,6 +240,24 @@ but before any resource and task declarations." :version "24.1" :type '(string :tag "Preamble")) +(defcustom org-export-taskjuggler-valid-task-attributes + '(account start note duration endbuffer endcredit end + flags journalentry length limits maxend maxstart minend + minstart period reference responsible scheduling + startbuffer startcredit statusnote) + "Valid attributes for Taskjuggler tasks. If one of these + appears as a property for a headline, it will be exported with + the corresponding task." + :group 'org-export-taskjuggler) + +(defcustom org-export-taskjuggler-valid-resource-attributes + '(limits vacation shift booking efficiency journalentry rate + workinghours flags) + "Valid attributes for Taskjuggler resources. If one of these + appears as a property for a headline, it will be exported with + the corresponding resource." + :group 'org-export-taskjuggler) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -614,7 +632,7 @@ is defined it will calculate a unique id for the resource using (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) (headline (cdr (assoc "headline" resource))) - (attributes '(limits vacation shift booking efficiency journalentry rate))) + (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat "resource " id " \"" headline "\" {\n " @@ -655,11 +673,7 @@ org-mode priority string." (cdr (assoc "duration" task)) (cdr (assoc "end" task)) (cdr (assoc "period" task))))))) - (attributes - '(account start note duration endbuffer endcredit end - flags journalentry length maxend maxstart minend - minstart period reference responsible scheduling - startbuffer startcredit statusnote))) + (attributes org-export-taskjuggler-valid-task-attributes)) (insert (concat "task " unique-id " \"" headline "\" {\n" -- 1.7.11.4
* org-taskjuggler.el (org-export-as-taskjuggler): Compute opt-plist, use `org-install-letbind'. --- lisp/org-taskjuggler.el | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7d9d203..529cda0 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -285,7 +285,10 @@ defined in `org-export-taskjuggler-default-reports'." (message "Exporting...") (setq-default org-done-keywords org-done-keywords) - (let* ((tasks + (let* ((opt-plist (org-combine-plists (org-default-export-plist) + (org-infile-export-plist))) + (org-export-opt-plist opt-plist) + (tasks (org-taskjuggler-resolve-dependencies (org-taskjuggler-assign-task-ids (org-taskjuggler-compute-task-leafiness @@ -336,6 +339,14 @@ defined in `org-export-taskjuggler-default-reports'." (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) + (org-install-letbind) + ;; create local variables for all options, to make sure all called + ;; functions get the correct information + (mapc (lambda (x) + (set (make-local-variable (nth 2 x)) + (plist-get opt-plist (car x)))) + org-export-plist-vars) + (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-date): Introduce new function to produce a taskjuggler-compatible date. (org-taskjuggler-components): Make use of SCHEDULED/DEADLINE properties. Infer start and end date from SCHEDULED/DEADLINE information. --- lisp/org-taskjuggler.el | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 529cda0..93f0cc7 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -138,8 +138,6 @@ ;; :END: ;; ;;;; * TODO -;; - Use SCHEDULED and DEADLINE information (not just start and end -;; properties). ;; - Look at org-file-properties, org-global-properties and ;; org-global-properties-fixed ;; - What about property inheritance and org-property-inherit-p? @@ -385,6 +383,10 @@ with the TaskJuggler GUI." (save-excursion (and (org-up-heading-safe) (org-entry-get (point) "ORDERED")))) +(defun org-taskjuggler-date (date) + (let ((time (parse-time-string date))) + (format "%d-%02d-%02d" (nth 5 time) (nth 4 time) (nth 3 time)))) + (defun org-taskjuggler-components () "Return an alist containing all the pertinent information for the current node such as the headline, the level, todo state @@ -396,6 +398,12 @@ information, all the properties, etc." (replace-regexp-in-string "\"" "\\\"" (nth 4 components) t t)) ; quote double quotes in headlines (parent-ordered (org-taskjuggler-parent-is-ordered-p))) + (let ((scheduled (assoc "SCHEDULED" props)) + (deadline (assoc "DEADLINE" props))) + (when scheduled + (push (cons "start" (org-taskjuggler-date (cdr scheduled))) props)) + (when deadline + (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) (push (cons "headline" headline) props) (push (cons "parent-ordered" parent-ordered) props))) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-open-task): Task with end-only is also a milestone (deadline), task with length is not. --- lisp/org-taskjuggler.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 93f0cc7..a18cdf8 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -689,8 +689,10 @@ org-mode priority string." (milestone (or (cdr (assoc "milestone" task)) (and (assoc "leaf-node" task) (not (or effort + (cdr (assoc "length" task)) (cdr (assoc "duration" task)) - (cdr (assoc "end" task)) + (and (cdr (assoc "start" task)) + (cdr (assoc "end" task))) (cdr (assoc "period" task))))))) (attributes org-export-taskjuggler-valid-task-attributes)) (insert -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-default-global-header): Add new option. (org-export-as-taskjuggler): Insert global header before anything else. --- lisp/org-taskjuggler.el | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index a18cdf8..c997da7 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -221,6 +221,14 @@ with `org-export-taskjuggler-project-tag'" :version "24.1" :type '(repeat (string :tag "Report"))) +(defcustom org-export-taskjuggler-default-global-header + "" + "Default global header for the project. This goes before +project declaration, and might be useful for early macros" + :group 'org-export-taskjuggler + :version "24.1" + :type '(string :tag "Preamble")) + (defcustom org-export-taskjuggler-default-global-properties "shift s40 \"Part time shift\" { workinghours wed, thu, fri off @@ -332,11 +340,6 @@ defined in `org-export-taskjuggler-default-reports'." (setcar tasks (push (cons "version" version) task)))) (with-current-buffer buffer (erase-buffer) - (org-clone-local-variables old-buffer "^org-") - (org-taskjuggler-open-project (car tasks)) - (insert org-export-taskjuggler-default-global-properties) - (insert "\n") - (dolist (resource resources) (org-install-letbind) ;; create local variables for all options, to make sure all called ;; functions get the correct information @@ -345,6 +348,12 @@ defined in `org-export-taskjuggler-default-reports'." (plist-get opt-plist (car x)))) org-export-plist-vars) + (org-clone-local-variables old-buffer "^org-") + (insert org-export-taskjuggler-default-global-header) + (org-taskjuggler-open-project (car tasks)) + (insert org-export-taskjuggler-default-global-properties) + (insert "\n") + (dolist (resource resources) (let ((level (cdr (assoc "level" resource)))) (org-taskjuggler-close-maybe level) (org-taskjuggler-open-resource resource) -- 1.7.11.4
* org-taskjuggler.el (org-taskjuggler-open-project): Use START - END as an alternative to START +Xd. --- lisp/org-taskjuggler.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index c997da7..7376302 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -615,9 +615,11 @@ specified it is calculated (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) (insert - (format "project %s \"%s\" \"%s\" %s +%sd {\n }\n" + (format "project %s \"%s\" \"%s\" %s %s {\n }\n" unique-id headline version start - org-export-taskjuggler-default-project-duration)))) + (or (and end (format "- %s" end)) + (format "+%sd" + org-export-taskjuggler-default-project-duration)))))) (defun org-taskjuggler-filter-and-join (items) "Filter all nil elements from ITEMS and join the remaining ones -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-keep-project-as-task): Add new option. (org-export-as-taskjuggler): Optionally drop the topmost "task" (project). (org-taskjuggler-assign-task-ids): Adapt path computation by optionally dropping the topmost component (project). Introduce `org-export-taskjuggler-keep-project-as-task' as a flag to toggle the behavior. Keep old behavior as default. --- lisp/org-taskjuggler.el | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 7376302..3c97e03 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -264,6 +264,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-keep-project-as-task t + "Whether to keep the project headline as an umbrella task for + all declared tasks. Setting this to nil will allow maintaining + completely separated task buckets, while still sharing the same + resources pool." + :group 'org-export-taskjuggler + :type 'boolean) + ;;; Hooks (defvar org-export-taskjuggler-final-hook nil @@ -350,7 +358,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-clone-local-variables old-buffer "^org-") (insert org-export-taskjuggler-default-global-header) - (org-taskjuggler-open-project (car tasks)) + (org-taskjuggler-open-project + (if org-export-taskjuggler-keep-project-as-task + (car tasks) + (pop tasks))) (insert org-export-taskjuggler-default-global-properties) (insert "\n") (dolist (resource resources) @@ -365,7 +376,9 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe level) (org-taskjuggler-open-task task) (setq org-export-taskjuggler-old-level level))) - (org-taskjuggler-close-maybe 1) + (org-taskjuggler-close-maybe + (if org-export-taskjuggler-keep-project-as-task + 1 2)) (org-taskjuggler-insert-reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") @@ -446,7 +459,11 @@ a path to the current task." (push unique-id (car unique-ids)) (setcar path unique-id))) (push (cons "unique-id" unique-id) task) - (push (cons "path" (mapconcat 'identity (reverse path) ".")) task) + (push (cons "path" + (mapconcat 'identity + (if org-export-taskjuggler-keep-project-as-task + (reverse path) + (cdr (reverse path))) ".")) task) (setq previous-level level) (setq resolved-tasks (append resolved-tasks (list task))))))) -- 1.7.11.4
--- lisp/org-taskjuggler.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 3c97e03..33b111d 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -329,7 +329,7 @@ defined in `org-export-taskjuggler-default-reports'." (unless resources (setq resources `((("resource_id" . ,(user-login-name)) - ("headline" . ,user-full-name) + ("HEADLINE" . ,user-full-name) ("level" . 1))))) ;; add a default allocation to the first task if none was given (unless (assoc "allocate" (car tasks)) @@ -427,7 +427,7 @@ information, all the properties, etc." (when deadline (push (cons "end" (org-taskjuggler-date (cdr deadline))) props))) (push (cons "level" level) props) - (push (cons "headline" headline) props) + (push (cons "HEADLINE" headline) props) (push (cons "parent-ordered" parent-ordered) props))) (defun org-taskjuggler-assign-task-ids (tasks) @@ -601,7 +601,7 @@ The id is derived from the headline and made unique against UNIQUE-IDS. If the (downcased) first token of the headline is not unique try to add more (downcased) tokens of the headline or finally add more underscore characters (\"_\")." - (let* ((headline (cdr (assoc "headline" item))) + (let* ((headline (cdr (assoc "HEADLINE" item))) (parts (split-string headline)) (id (org-taskjuggler-clean-id (downcase (pop parts))))) ; try to add more parts of the headline to make it unique @@ -627,7 +627,7 @@ attributes from the PROJECT alist are inserted. If no end date is specified it is calculated `org-export-taskjuggler-default-project-duration' days from now." (let* ((unique-id (cdr (assoc "unique-id" project))) - (headline (cdr (assoc "headline" project))) + (headline (cdr (assoc "HEADLINE" project))) (version (cdr (assoc "version" project))) (start (cdr (assoc "start" project))) (end (cdr (assoc "end" project)))) @@ -678,7 +678,7 @@ is defined it will calculate a unique id for the resource using (or (cdr (assoc "resource_id" resource)) (cdr (assoc "ID" resource)) (cdr (assoc "unique-id" resource))))) - (headline (cdr (assoc "headline" resource))) + (headline (cdr (assoc "HEADLINE" resource))) (attributes org-export-taskjuggler-valid-resource-attributes)) (insert (concat @@ -703,7 +703,7 @@ org-mode priority string." (defun org-taskjuggler-open-task (task) (let* ((unique-id (cdr (assoc "unique-id" task))) - (headline (cdr (assoc "headline" task))) + (headline (cdr (assoc "HEADLINE" task))) (effort (org-taskjuggler-clean-effort (cdr (assoc org-effort-property task)))) (depends (cdr (assoc "depends" task))) (allocate (cdr (assoc "allocate" task))) -- 1.7.11.4
* org-taskjuggler.el (org-export-taskjuggler-report-tag): Add new option. (org-export-taskjuggler-valid-report-attributes): Add new option. (org-export-as-taskjuggler): Compute reports. (org-taskjuggler-open-report): Generate report from org item. (org-taskjuggler-insert-reports): Insert default reports only if no explicit one is defined. --- lisp/org-taskjuggler.el | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 33b111d..49c24ff 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -181,6 +181,13 @@ resources for the project." :version "24.1" :type 'string) +(defcustom org-export-taskjuggler-report-tag "taskjuggler_report" + "Tag, property or todo used to find the tree containing all the +reports for the project." + :group 'org-export-taskjuggler + :version "24.1" + :type 'string) + (defcustom org-export-taskjuggler-target-version 2.4 "Which version of TaskJuggler the exporter is targeting." :group 'org-export-taskjuggler @@ -264,6 +271,14 @@ but before any resource and task declarations." the corresponding resource." :group 'org-export-taskjuggler) +(defcustom org-export-taskjuggler-valid-report-attributes + '(headline columns definitions timeformat hideresource hidetask + loadunit sorttasks formats period) + "Valid attributes for Taskjuggler reports. If one of these + appears as a property for a headline, it will be exported with + the corresponding report." + :group 'org-export-taskjuggler) + (defcustom org-export-taskjuggler-keep-project-as-task t "Whether to keep the project headline as an umbrella task for all declared tasks. Setting this to nil will allow maintaining @@ -314,6 +329,10 @@ defined in `org-export-taskjuggler-default-reports'." (org-map-entries 'org-taskjuggler-components org-export-taskjuggler-resource-tag nil 'archive 'comment))) + (reports + (org-map-entries + 'org-taskjuggler-components + org-export-taskjuggler-report-tag nil 'archive 'comment)) (filename (expand-file-name (concat (file-name-sans-extension @@ -379,7 +398,7 @@ defined in `org-export-taskjuggler-default-reports'." (org-taskjuggler-close-maybe (if org-export-taskjuggler-keep-project-as-task 1 2)) - (org-taskjuggler-insert-reports) + (org-taskjuggler-insert-reports reports) (save-buffer) (or (org-export-push-to-kill-ring "TaskJuggler") (message "Exporting... done")) @@ -741,6 +760,16 @@ org-mode priority string." (org-taskjuggler-get-attributes task attributes) "\n")))) +(defun org-taskjuggler-open-report (report) + (let* ((kind (or (cdr (assoc "report-kind" report)) "taskreport")) + (headline (cdr (assoc "HEADLINE" report))) + (attributes org-export-taskjuggler-valid-report-attributes)) + (insert + (concat + kind " \"" headline "\" {\n" + (org-taskjuggler-get-attributes report attributes) + "\n}\n")))) + (defun org-taskjuggler-close-maybe (level) (while (> org-export-taskjuggler-old-level level) (insert "}\n") @@ -748,10 +777,13 @@ org-mode priority string." (when (= org-export-taskjuggler-old-level level) (insert "}\n"))) -(defun org-taskjuggler-insert-reports () - (let (report) - (dolist (report org-export-taskjuggler-default-reports) - (insert report "\n")))) +(defun org-taskjuggler-insert-reports (reports) + (if reports + (dolist (report (cdr reports)) + (org-taskjuggler-open-report report)) + (let (report) + (dolist (report org-export-taskjuggler-default-reports) + (insert report "\n"))))) (provide 'org-taskjuggler) -- 1.7.11.4
--- doc/org.texi | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 3fdb4ac..0f8b0d9 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -11898,9 +11898,9 @@ nodes of a document or strictly follow the order of the nodes in the document. Instead the TaskJuggler exporter looks for a tree that defines the tasks and -a optionally tree that defines the resources for this project. It then -creates a TaskJuggler file based on these trees and the attributes defined in -all the nodes. +optionally trees that define the resources and reports for this project. +It then creates a TaskJuggler file based on these trees and the attributes +defined in all the nodes. @subsection TaskJuggler export commands @@ -11909,7 +11909,8 @@ all the nodes. Export as a TaskJuggler file. @orgcmd{C-c C-e J,org-export-as-taskjuggler-and-open} -Export as a TaskJuggler file and then open the file with TaskJugglerUI. +Export as a TaskJuggler file and then open the file with TaskJugglerUI (only +for TaskJugglerUI 2.x). @end table @subsection Tasks @@ -11947,15 +11948,17 @@ time. @subsection Export of properties -The exporter also takes TODO state information into consideration, i.e.@: if a -task is marked as done it will have the corresponding attribute in -TaskJuggler (@samp{complete 100}). Also it will export any property on a task -resource or resource node which is known to TaskJuggler, such as -@samp{limits}, @samp{vacation}, @samp{shift}, @samp{booking}, -@samp{efficiency}, @samp{journalentry}, @samp{rate} for resources or -@samp{account}, @samp{start}, @samp{note}, @samp{duration}, @samp{end}, -@samp{journalentry}, @samp{milestone}, @samp{reference}, @samp{responsible}, -@samp{scheduling}, etc for tasks. +The exporter also takes TODO state information into consideration, i.e.@: if +a task is marked as done it will have the corresponding attribute in +TaskJuggler (@samp{complete 100}). Scheduling information is also taken into +account to set start/end dates for tasks. + +The exporter will also export any property on a task resource or resource +node which is known to TaskJuggler, such as @samp{limits}, @samp{vacation}, +@samp{shift}, @samp{booking}, @samp{efficiency}, @samp{journalentry}, +@samp{rate} for resources or @samp{account}, @samp{start}, @samp{note}, +@samp{duration}, @samp{end}, @samp{journalentry}, @samp{milestone}, +@samp{reference}, @samp{responsible}, @samp{scheduling}, etc for tasks. @subsection Dependencies @@ -12001,11 +12004,20 @@ examples should illustrate this: @vindex org-export-taskjuggler-default-reports TaskJuggler can produce many kinds of reports (e.g.@: gantt chart, resource allocation, etc). The user defines what kind of reports should be generated -for a project in the TaskJuggler file. The exporter will automatically insert -some default reports in the file. These defaults are defined in -@code{org-export-taskjuggler-default-reports}. They can be modified using -customize along with a number of other options. For a more complete list, see -@kbd{M-x customize-group @key{RET} org-export-taskjuggler @key{RET}}. +for a project in the TaskJuggler file. By default, the exporter will +automatically insert some pre-set reports in the file. These defaults are +defined in @code{org-export-taskjuggler-default-reports}. They can be +modified using customize along with a number of other options. For a more +complete list, see @kbd{M-x customize-group @key{RET} org-export-taskjuggler +@key{RET}}. + +Alternately, the user can tag a tree with +@code{org-export-taskjuggler-report-tag}, and define reports in sub-nodes, +similarly to what is done with tasks or resources. The properties used for +report generation are defined in +@code{org-export-taskjuggler-valid-report-attributes}. In addition, a special +property named @samp{report-kind} is used to define the kind of report one +wants to generate (by default, a @samp{taskreport}). For more information and examples see the Org-taskjuggler tutorial at @uref{http://orgmode.org/worg/org-tutorials/org-taskjuggler.html}. -- 1.7.11.4
* lisp/org-publish.el (org-publish-org-to-taskjuggler): New function to publish taskjuggler projects. * lisp/org-taskjuggler.el (org-export-as-taskjuggler): Adapt signature to reflect standard interface, in particular allow export to buffer. --- lisp/org-publish.el | 6 ++++++ lisp/org-taskjuggler.el | 33 +++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lisp/org-publish.el b/lisp/org-publish.el index ed2db3a..e78e2d4 100644 --- a/lisp/org-publish.el +++ b/lisp/org-publish.el @@ -649,6 +649,12 @@ See `org-publish-org-to' to the list of arguments." (org-publish-with-aux-preprocess-maybe (org-publish-org-to "utf8" plist filename pub-dir))) +(defun org-publish-org-to-taskjuggler (plist filename pub-dir) + "Publish an org file to TaskJuggler. +See `org-publish-org-to' to the list of arguments." + (org-publish-with-aux-preprocess-maybe + (org-publish-org-to "taskjuggler" plist filename pub-dir))) + (defun org-publish-attachment (plist filename pub-dir) "Publish a file with no transformation of any kind. See `org-publish-org-to' to the list of arguments." diff --git a/lisp/org-taskjuggler.el b/lisp/org-taskjuggler.el index 49c24ff..1733fe8 100644 --- a/lisp/org-taskjuggler.el +++ b/lisp/org-taskjuggler.el @@ -298,7 +298,8 @@ but before any resource and task declarations." (defvar org-export-taskjuggler-old-level) ;;;###autoload -(defun org-export-as-taskjuggler () +(defun org-export-as-taskjuggler (&optional arg hidden ext-plist + to-buffer body-only pub-dir) "Export parts of the current buffer as a TaskJuggler file. The exporter looks for a tree with tag, property or todo that matches `org-export-taskjuggler-project-tag' and takes this as @@ -310,11 +311,12 @@ resources for the project. If no resources are specified, a default resource is created and allocated to the project. Also the taskjuggler project will be created with default reports as defined in `org-export-taskjuggler-default-reports'." - (interactive) + (interactive "P") (message "Exporting...") (setq-default org-done-keywords org-done-keywords) (let* ((opt-plist (org-combine-plists (org-default-export-plist) + ext-plist (org-infile-export-plist))) (org-export-opt-plist opt-plist) (tasks @@ -333,12 +335,20 @@ defined in `org-export-taskjuggler-default-reports'." (org-map-entries 'org-taskjuggler-components org-export-taskjuggler-report-tag nil 'archive 'comment)) - (filename (expand-file-name - (concat - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)) - org-export-taskjuggler-extension))) - (buffer (find-file-noselect filename)) + (filename (if to-buffer + nil + (concat (file-name-as-directory + (or pub-dir + (org-export-directory :tj opt-plist))) + (file-name-sans-extension + (file-name-nondirectory buffer-file-name)) + org-export-taskjuggler-extension))) + (buffer (if to-buffer + (cond + ((eq to-buffer 'string) + (get-buffer-create "*Org Taskjuggler Export*")) + (t (get-buffer-create to-buffer))) + (find-file-noselect filename))) (old-buffer (current-buffer)) (org-export-taskjuggler-old-level 0) task resource) @@ -399,10 +409,13 @@ defined in `org-export-taskjuggler-default-reports'." (if org-export-taskjuggler-keep-project-as-task 1 2)) (org-taskjuggler-insert-reports reports) - (save-buffer) + (or to-buffer (save-buffer)) (or (org-export-push-to-kill-ring "TaskJuggler") (message "Exporting... done")) - (current-buffer)))) + (if (eq to-buffer 'string) + (prog1 (buffer-substring (point-min) (point-max)) + (kill-buffer (current-buffer))) + (current-buffer))))) ;;;###autoload (defun org-export-as-taskjuggler-and-open () -- 1.7.11.4
Hi Yann,
Yann Hodique <yann.hodique@gmail.com> writes:
>>>>>> "Bastien" == Bastien <bzg@altern.org> writes:
>
>> Thanks for this effort -- not nitpicking, but there is room left for
>> small improvements.
>
> Sure, no problem. I will do that right away.
Thanks for the v3 :)
--
Bastien
Hi Yann,
Yann Hodique <yann.hodique@gmail.com> writes:
> here is a new version of the patch series.
I have now applied those patches to master.
Thanks a lot for this!
--
Bastien
Hi Yann Bastien <bzg@altern.org> writes: > I have now applied those patches to master. I guess we should update the tutorial on worg (http://orgmode.org/worg/org-tutorials/org-taskjuggler.html). Would you have time to have a stab at this? Thanks Christian -- Christian Egli Swiss Library for the Blind, Visually Impaired and Print Disabled Grubenstrasse 12, CH-8045 Zürich, Switzerland