Implement TODO statistics.
This uses the same cookies as Checkbox statistics, [%] and [/]
This commit is contained in:
parent
24fd4650de
commit
2c0812caf1
|
@ -9,9 +9,40 @@
|
||||||
#+LINK_HOME: http://orgmode.org
|
#+LINK_HOME: http://orgmode.org
|
||||||
|
|
||||||
* Version 6.04
|
* Version 6.04
|
||||||
|
:PROPERTIES:
|
||||||
|
:VISIBILITY: content
|
||||||
|
:END:
|
||||||
|
|
||||||
** Details
|
** Details
|
||||||
|
|
||||||
|
*** Statistics for TODO entries
|
||||||
|
|
||||||
|
The [/] and [%] cookies have already provided statistics for
|
||||||
|
checkboxes. Now they do the same also for TODO entries. So if a
|
||||||
|
headline contains either cookie, changing the TODO state of any
|
||||||
|
direct child will trigger an update of this cookie. Children
|
||||||
|
that are neither TODO nor DONE are ignored.
|
||||||
|
|
||||||
|
There have already been requests to automatically switch the
|
||||||
|
parent headline to DONE when all children are done. I am not
|
||||||
|
makeing this a default feature, because one needs to make many
|
||||||
|
decisions about which keyword to use etc. Instead of a complex
|
||||||
|
customization variable, I am providing a hook that can be used.
|
||||||
|
This hook will be called each time a TODO statistics cookie is
|
||||||
|
updated, with the cursor in the corresponding line. Each
|
||||||
|
function in the hook will receive two arguments, the number of
|
||||||
|
done entries, and the number of not-done entries. Here is a
|
||||||
|
example implementation:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun org-summary-todo (n-done n-not-done)
|
||||||
|
"Switch entry to DONE when all subentries are done, to TODO otherwise."
|
||||||
|
(let (org-log-done org-log-states) ; turn off logging
|
||||||
|
(org-todo (if (= n-not-done 0) "DONE" "TODO"))))
|
||||||
|
|
||||||
|
(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
*** iCalendar now defines proper UIDs for entries
|
*** iCalendar now defines proper UIDs for entries
|
||||||
|
|
||||||
This is necessary for synchronization services. The UIDs are
|
This is necessary for synchronization services. The UIDs are
|
||||||
|
@ -36,9 +67,6 @@ but a synchronization program can still figure out from which
|
||||||
entry all the different instances originate.
|
entry all the different instances originate.
|
||||||
|
|
||||||
* Version 6.03
|
* Version 6.03
|
||||||
:PROPERTIES:
|
|
||||||
:VISIBILITY: content
|
|
||||||
:END:
|
|
||||||
|
|
||||||
** Overview
|
** Overview
|
||||||
|
|
||||||
|
|
37
doc/org.texi
37
doc/org.texi
|
@ -3171,12 +3171,37 @@ priority):
|
||||||
@cindex tasks, breaking down
|
@cindex tasks, breaking down
|
||||||
|
|
||||||
It is often advisable to break down large tasks into smaller, manageable
|
It is often advisable to break down large tasks into smaller, manageable
|
||||||
subtasks. You can do this by creating an outline tree below a TODO
|
subtasks. You can do this by creating an outline tree below a TODO item,
|
||||||
item, with detailed subtasks on the tree@footnote{To keep subtasks out
|
with detailed subtasks on the tree@footnote{To keep subtasks out of the
|
||||||
of the global TODO list, see the
|
global TODO list, see the @code{org-agenda-todo-list-sublevels}.}. To keep
|
||||||
@code{org-agenda-todo-list-sublevels}.}. Another possibility is the use
|
the overview over the fraction of subtasks that are already completed, insert
|
||||||
of checkboxes to identify (a hierarchy of) a large number of subtasks
|
either @samp{[/]} or @samp{[%]} anywhere in the headline. These cookies will
|
||||||
(@pxref{Checkboxes}).
|
be updates each time the todo status of a child changes. For example:
|
||||||
|
|
||||||
|
@example
|
||||||
|
* Organize Party [33%]
|
||||||
|
** TODO Call people [1/2]
|
||||||
|
*** TODO Peter
|
||||||
|
*** DONE Sarah
|
||||||
|
** TODO Buy food
|
||||||
|
** DONE Talk to neighbor
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If you would like a TODO entry to automatically change to DONE when all
|
||||||
|
chilrden are done, you can use the following setup:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(defun org-summary-todo (n-done n-not-done)
|
||||||
|
"Switch entry to DONE when all subentries are done, to TODO otherwise."
|
||||||
|
(let (org-log-done org-log-states) ; turn off logging
|
||||||
|
(org-todo (if (= n-not-done 0) "DONE" "TODO"))))
|
||||||
|
|
||||||
|
(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
Another possibility is the use of checkboxes to identify (a hierarchy of) a
|
||||||
|
large number of subtasks (@pxref{Checkboxes}).
|
||||||
|
|
||||||
|
|
||||||
@node Checkboxes, , Breaking down tasks, TODO Items
|
@node Checkboxes, , Breaking down tasks, TODO Items
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
2008-05-19 Carsten Dominik <dominik@science.uva.nl>
|
2008-05-19 Carsten Dominik <dominik@science.uva.nl>
|
||||||
|
|
||||||
|
* org.el (org-update-parent-todo-statistics): New function.
|
||||||
|
|
||||||
* org-exp.el (org-icalendar-store-UID): New option.
|
* org-exp.el (org-icalendar-store-UID): New option.
|
||||||
(org-icalendar-force-UID): Option removed.
|
(org-icalendar-force-UID): Option removed.
|
||||||
(org-print-icalendar-entries): IMplement UIDs.
|
(org-print-icalendar-entries): IMplement UIDs.
|
||||||
|
|
|
@ -3860,7 +3860,7 @@ END:VEVENT\n"
|
||||||
UID: %s
|
UID: %s
|
||||||
%s
|
%s
|
||||||
SUMMARY:%s%s%s
|
SUMMARY:%s%s%s
|
||||||
CATEGORIES:%s%s
|
CATEGORIES:%s
|
||||||
SEQUENCE:1
|
SEQUENCE:1
|
||||||
PRIORITY:%d
|
PRIORITY:%d
|
||||||
STATUS:%s
|
STATUS:%s
|
||||||
|
|
60
lisp/org.el
60
lisp/org.el
|
@ -174,6 +174,7 @@ to add the symbol `xyz', and the package must have a call to
|
||||||
(const :tag " mouse: Additional mouse support" org-mouse)
|
(const :tag " mouse: Additional mouse support" org-mouse)
|
||||||
|
|
||||||
(const :tag "C annotate-file: Annotate a file with org syntax" org-annotate-file)
|
(const :tag "C annotate-file: Annotate a file with org syntax" org-annotate-file)
|
||||||
|
(const :tag "C annotation-helper: Call Remeber directly from Browser" org-annotation-helper)
|
||||||
(const :tag "C bookmark: Org links to bookmarks" org-bookmark)
|
(const :tag "C bookmark: Org links to bookmarks" org-bookmark)
|
||||||
(const :tag "C depend: TODO dependencies for Org-mode" org-depend)
|
(const :tag "C depend: TODO dependencies for Org-mode" org-depend)
|
||||||
(const :tag "C elisp-symbol: Org links to emacs-lisp symbols" org-elisp-symbol)
|
(const :tag "C elisp-symbol: Org links to emacs-lisp symbols" org-elisp-symbol)
|
||||||
|
@ -1388,6 +1389,13 @@ by a letter in parenthesis, like TODO(t)."
|
||||||
(const :tag "By default" t)
|
(const :tag "By default" t)
|
||||||
(const :tag "Only with C-u C-c C-t" prefix)))
|
(const :tag "Only with C-u C-c C-t" prefix)))
|
||||||
|
|
||||||
|
(defcustom org-provide-todo-statistics t
|
||||||
|
"Non-nil means, update todo statistics after insert and toggle.
|
||||||
|
When this is set, todo statistics is updated in the parent of the current
|
||||||
|
entry each time a todo state is changed."
|
||||||
|
:group 'org-todo
|
||||||
|
:type 'boolean)
|
||||||
|
|
||||||
(defcustom org-after-todo-state-change-hook nil
|
(defcustom org-after-todo-state-change-hook nil
|
||||||
"Hook which is run after the state of a TODO item was changed.
|
"Hook which is run after the state of a TODO item was changed.
|
||||||
The new state (a string with a TODO keyword, or nil) is available in the
|
The new state (a string with a TODO keyword, or nil) is available in the
|
||||||
|
@ -2367,6 +2375,7 @@ If TABLE-TYPE is non-nil, also check for table.el-type tables."
|
||||||
org-replace-region-by-html org-export-region-as-html
|
org-replace-region-by-html org-export-region-as-html
|
||||||
org-export-as-html org-export-icalendar-this-file
|
org-export-as-html org-export-icalendar-this-file
|
||||||
org-export-icalendar-all-agenda-files
|
org-export-icalendar-all-agenda-files
|
||||||
|
org-table-clean-before-export
|
||||||
org-export-icalendar-combine-agenda-files org-export-as-xoxo)))
|
org-export-icalendar-combine-agenda-files org-export-as-xoxo)))
|
||||||
|
|
||||||
;; Declare and autoload functions from org-exp.el
|
;; Declare and autoload functions from org-exp.el
|
||||||
|
@ -4546,7 +4555,9 @@ state (TODO by default). Also with prefix arg, force first state."
|
||||||
(not (match-beginning 2))
|
(not (match-beginning 2))
|
||||||
(member (match-string 2) org-done-keywords))
|
(member (match-string 2) org-done-keywords))
|
||||||
(insert (car org-todo-keywords-1) " ")
|
(insert (car org-todo-keywords-1) " ")
|
||||||
(insert (match-string 2) " "))))
|
(insert (match-string 2) " "))
|
||||||
|
(when org-provide-todo-statistics
|
||||||
|
(org-update-parent-todo-statistics))))
|
||||||
|
|
||||||
(defun org-insert-subheading (arg)
|
(defun org-insert-subheading (arg)
|
||||||
"Insert a new subheading and demote it.
|
"Insert a new subheading and demote it.
|
||||||
|
@ -8186,6 +8197,8 @@ For calling through lisp, arg is also interpreted in the following way:
|
||||||
(org-add-log-setup 'state state 'findpos dolog)))
|
(org-add-log-setup 'state state 'findpos dolog)))
|
||||||
;; Fixup tag positioning
|
;; Fixup tag positioning
|
||||||
(and org-auto-align-tags (not org-setting-tags) (org-set-tags nil t))
|
(and org-auto-align-tags (not org-setting-tags) (org-set-tags nil t))
|
||||||
|
(when org-provide-todo-statistics
|
||||||
|
(org-update-parent-todo-statistics))
|
||||||
(run-hooks 'org-after-todo-state-change-hook)
|
(run-hooks 'org-after-todo-state-change-hook)
|
||||||
(if (and arg (not (member state org-done-keywords)))
|
(if (and arg (not (member state org-done-keywords)))
|
||||||
(setq head (org-get-todo-sequence-head state)))
|
(setq head (org-get-todo-sequence-head state)))
|
||||||
|
@ -8205,6 +8218,51 @@ For calling through lisp, arg is also interpreted in the following way:
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(run-hook-with-args 'org-trigger-hook change-plist)))))))
|
(run-hook-with-args 'org-trigger-hook change-plist)))))))
|
||||||
|
|
||||||
|
(defun org-update-parent-todo-statistics ()
|
||||||
|
"Update any statistics cookie in the parent of the current headline."
|
||||||
|
(interactive)
|
||||||
|
(let ((box-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
|
||||||
|
level (cnt-all 0) (cnt-done 0) is-percent kwd)
|
||||||
|
(catch 'exit
|
||||||
|
(save-excursion
|
||||||
|
(setq level (org-up-heading-safe))
|
||||||
|
(unless (and level
|
||||||
|
(re-search-forward box-re (point-at-eol) t))
|
||||||
|
(throw 'exit nil))
|
||||||
|
(setq is-percent (match-end 2))
|
||||||
|
(save-match-data
|
||||||
|
(unless (outline-next-heading) (throw 'exit nil))
|
||||||
|
(while (looking-at org-todo-line-regexp)
|
||||||
|
(setq kwd (match-string 2))
|
||||||
|
(and kwd (setq cnt-all (1+ cnt-all)))
|
||||||
|
(and (member kwd org-done-keywords)
|
||||||
|
(setq cnt-done (1+ cnt-done)))
|
||||||
|
(condition-case nil
|
||||||
|
(outline-forward-same-level 1)
|
||||||
|
(error (end-of-line 1)))))
|
||||||
|
(replace-match
|
||||||
|
(if is-percent
|
||||||
|
(format "[%d%%]" (/ (* 100 cnt-done) (max 1 cnt-all)))
|
||||||
|
(format "[%d/%d]" cnt-done cnt-all)))
|
||||||
|
(run-hook-with-args 'org-after-todo-statistics-hook
|
||||||
|
cnt-done (- cnt-all cnt-done))))))
|
||||||
|
|
||||||
|
(defvar org-after-todo-statistics-hook nil
|
||||||
|
"Hook that is called after a TODO statistics cookie has been updated.
|
||||||
|
Each function is called with two arguments: the number of not-done entries
|
||||||
|
and the number of done entries.
|
||||||
|
|
||||||
|
For example, the following function, when added to this hook, will switch
|
||||||
|
an entry to DONE when all children are done, and back to TODO when new
|
||||||
|
entries are set to a TODO status. Note that this hook is only called
|
||||||
|
when there is a statistics cookie in the headline!
|
||||||
|
|
||||||
|
(defun org-summary-todo (n-done n-not-done)
|
||||||
|
\"Switch entry to DONE when all subentries are done, to TODO otherwise.\"
|
||||||
|
(let (org-log-done org-log-states) ; turn off logging
|
||||||
|
(org-todo (if (= n-not-done 0) \"DONE\" \"TODO\"))))
|
||||||
|
")
|
||||||
|
|
||||||
(defun org-local-logging (value)
|
(defun org-local-logging (value)
|
||||||
"Get logging settings from a property VALUE."
|
"Get logging settings from a property VALUE."
|
||||||
(let* (words w a)
|
(let* (words w a)
|
||||||
|
|
Loading…
Reference in New Issue