0
0
Fork 1
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-08-26 14:32:52 +00:00

TODO statistics: Allow recursive statistics

Setting the new option `org-hierarchical-todo-statistics' to nil will
make TODO statistics to be computed recursively.  This means, not only
the direct children of a node contribute to its TODO statistics, but
the entire subtree.

You can also set the COOKIE_DATA property and add the word "recursive"
there to get recursive statistics for a specific tree.
This commit is contained in:
Carsten Dominik 2009-05-19 23:05:01 +02:00
parent 83e82f9ccd
commit f54ff074d2
3 changed files with 79 additions and 38 deletions

View file

@ -1,3 +1,12 @@
2009-05-20 Carsten Dominik <carsten.dominik@gmail.com>
* org-list.el (org-update-checkbox-count): Make property
dependent.
* org.el (org-hierarchical-todo-statistics): New option.
(org-update-parent-todo-statistics): Modified to handle recursive
statistics.
2009-05-19 Carsten Dominik <carsten.dominik@gmail.com> 2009-05-19 Carsten Dominik <carsten.dominik@gmail.com>
* org-publish.el (org-publish): Make this function behave * org-publish.el (org-publish): Make this function behave

View file

@ -393,6 +393,10 @@ the whole buffer."
(re-find (concat re "\\|" re-box)) (re-find (concat re "\\|" re-box))
beg-cookie end-cookie is-percent c-on c-off lim beg-cookie end-cookie is-percent c-on c-off lim
eline curr-ind next-ind continue-from startsearch eline curr-ind next-ind continue-from startsearch
(recursive
(or (not org-hierarchical-checkbox-statistics)
(string-match "\\<recursive\\>"
(or (org-entry-get nil "COOKIE_DATA") ""))))
(cstat 0) (cstat 0)
) )
(when all (when all
@ -404,12 +408,11 @@ the whole buffer."
(while (and (re-search-backward re-find beg t) (while (and (re-search-backward re-find beg t)
(not (save-match-data (not (save-match-data
(and (org-on-heading-p) (and (org-on-heading-p)
(string-match "\\<todo\\>"
(equal (downcase (downcase
(or (org-entry-get (or (org-entry-get
nil "COOKIE_DATA") nil "COOKIE_DATA")
"")) "")))))))
"todo")))))
(setq beg-cookie (match-beginning 1) (setq beg-cookie (match-beginning 1)
end-cookie (match-end 1) end-cookie (match-end 1)
cstat (+ cstat (if end-cookie 1 0)) cstat (+ cstat (if end-cookie 1 0))
@ -432,9 +435,9 @@ the whole buffer."
(setq curr-ind (org-get-indentation)) (setq curr-ind (org-get-indentation))
(setq next-ind curr-ind) (setq next-ind curr-ind)
(while (and (bolp) (org-at-item-p) (while (and (bolp) (org-at-item-p)
(if org-hierarchical-checkbox-statistics (if recursive
(= curr-ind next-ind) (<= curr-ind next-ind)
(<= curr-ind next-ind))) (= curr-ind next-ind)))
(save-excursion (end-of-line) (setq eline (point))) (save-excursion (end-of-line) (setq eline (point)))
(if (re-search-forward re-box eline t) (if (re-search-forward re-box eline t)
(if (member (match-string 2) '("[ ]" "[-]")) (if (member (match-string 2) '("[ ]" "[-]"))
@ -442,7 +445,7 @@ the whole buffer."
(setq c-on (1+ c-on)) (setq c-on (1+ c-on))
) )
) )
(if org-hierarchical-checkbox-statistics (if (not recursive)
(org-end-of-item) (org-end-of-item)
(end-of-line) (end-of-line)
(when (re-search-forward org-list-beginning-re lim t) (when (re-search-forward org-list-beginning-re lim t)

View file

@ -1737,6 +1737,13 @@ entry each time a todo state is changed."
:group 'org-todo :group 'org-todo
:type 'boolean) :type 'boolean)
(defcustom org-hierarchical-todo-statistics t
"Non-nil means, TODO statistics covers just direct children.
When nil, all entries in the subtree are considered.
This has only an effect if `org-provide-todo-statistics' is set."
: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
@ -9442,37 +9449,59 @@ changes because there are uncheckd boxes in this entry."
t)) ; do not block t)) ; do not block
(defun org-update-parent-todo-statistics () (defun org-update-parent-todo-statistics ()
"Update any statistics cookie in the parent of the current headline." "Update any statistics cookie in the parent of the current headline.
When `org-hierarchical-todo-statistics' is nil, statistics will cover
the entire subtree and this will travel up the hierarchy and update
statistics everywhere."
(interactive) (interactive)
(let ((box-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)") (let* ((lim 0) prop
level (cnt-all 0) (cnt-done 0) is-percent kwd cookie-present) (recursive (or (not org-hierarchical-todo-statistics)
(string-match
"\\<recursive\\>"
(or (setq prop (org-entry-get
nil "COOKIE_DATA" 'inherit)) ""))))
(lim (or (and prop (marker-position
org-entry-property-inherited-from))
lim))
(first t)
(box-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
level ltoggle l1
(cnt-all 0) (cnt-done 0) is-percent kwd cookie-present)
(catch 'exit (catch 'exit
(save-excursion (save-excursion
(setq level (org-up-heading-safe)) (beginning-of-line 1)
(unless (and level (if (org-at-heading-p)
(not (equal (downcase (setq ltoggle (funcall outline-level))
(or (org-entry-get (error "This should not happen"))
nil "COOKIE_DATA") (while (and (setq level (org-up-heading-safe))
"")) (or recursive first)
"checkbox"))) (>= (point) lim))
(throw 'exit nil)) (setq first nil)
(while (re-search-forward box-re (point-at-eol) t) (unless (and level
(setq cnt-all 0 cnt-done 0 cookie-present t) (not (string-match
(setq is-percent (match-end 2)) "\\<checkbox\\>"
(save-match-data (downcase
(unless (outline-next-heading) (throw 'exit nil)) (or (org-entry-get
(while (looking-at org-todo-line-regexp) nil "COOKIE_DATA")
(setq kwd (match-string 2)) "")))))
(and kwd (setq cnt-all (1+ cnt-all))) (throw 'exit nil))
(and (member kwd org-done-keywords) (while (re-search-forward box-re (point-at-eol) t)
(setq cnt-done (1+ cnt-done))) (setq cnt-all 0 cnt-done 0 cookie-present t)
(condition-case nil (setq is-percent (match-end 2))
(org-forward-same-level 1) (save-match-data
(error (end-of-line 1))))) (unless (outline-next-heading) (throw 'exit nil))
(replace-match (while (and (looking-at org-complex-heading-regexp)
(if is-percent (> (setq l1 (length (match-string 1))) level))
(format "[%d%%]" (/ (* 100 cnt-done) (max 1 cnt-all))) (setq kwd (and (or recursive (= l1 ltoggle))
(format "[%d/%d]" cnt-done cnt-all)))) (match-string 2)))
(and kwd (setq cnt-all (1+ cnt-all)))
(and (member kwd org-done-keywords)
(setq cnt-done (1+ cnt-done)))
(outline-next-heading)))
(replace-match
(if is-percent
(format "[%d%%]" (/ (* 100 cnt-done) (max 1 cnt-all)))
(format "[%d/%d]" cnt-done cnt-all)))))
(when cookie-present (when cookie-present
(run-hook-with-args 'org-after-todo-statistics-hook (run-hook-with-args 'org-after-todo-statistics-hook
cnt-done (- cnt-all cnt-done))))) cnt-done (- cnt-all cnt-done)))))