Function: org-block-todo-from-children-or-siblings-or-parent
org-block-todo-from-children-or-siblings-or-parent is a byte-compiled
function defined in org.el.gz.
Signature
(org-block-todo-from-children-or-siblings-or-parent CHANGE-PLIST)
Documentation
Block turning an entry into a TODO, using the hierarchy.
This checks whether the current task should be blocked from state changes. Such blocking occurs when:
1. The task has children which are not all in a completed state.
2. A task has a parent with the property :ORDERED:, and there
are siblings prior to the current task with incomplete
status.
3. The parent of the task is blocked because it has siblings that should
be done first, or is child of a block grandparent TODO entry.
Source Code
;; Defined in /usr/src/emacs/lisp/org/org.el.gz
(defun org-block-todo-from-children-or-siblings-or-parent (change-plist)
"Block turning an entry into a TODO, using the hierarchy.
This checks whether the current task should be blocked from state
changes. Such blocking occurs when:
1. The task has children which are not all in a completed state.
2. A task has a parent with the property :ORDERED:, and there
are siblings prior to the current task with incomplete
status.
3. The parent of the task is blocked because it has siblings that should
be done first, or is child of a block grandparent TODO entry."
(if (not org-enforce-todo-dependencies)
t ; if locally turned off don't block
(catch 'dont-block
;; If this is not a todo state change, or if this entry is already DONE,
;; do not block
(when (or (not (eq (plist-get change-plist :type) 'todo-state-change))
(member (plist-get change-plist :from)
(cons 'done org-done-keywords))
(member (plist-get change-plist :to)
(cons 'todo org-not-done-keywords))
(not (plist-get change-plist :to)))
(throw 'dont-block t))
;; If this task has children, and any are undone, it's blocked
(save-excursion
(org-back-to-heading t)
(let ((this-level (funcall outline-level)))
(outline-next-heading)
(let ((child-level (funcall outline-level)))
(while (and (not (eobp))
(> child-level this-level))
;; this todo has children, check whether they are all
;; completed
(when (and (not (org-entry-is-done-p))
(org-entry-is-todo-p))
(setq org-block-entry-blocking (org-get-heading))
(throw 'dont-block nil))
(outline-next-heading)
(setq child-level (funcall outline-level))))))
;; Otherwise, if the task's parent has the :ORDERED: property, and
;; any previous siblings are undone, it's blocked
(save-excursion
(org-back-to-heading t)
(let* ((pos (point))
(parent-pos (and (org-up-heading-safe) (point)))
(case-fold-search nil))
(unless parent-pos (throw 'dont-block t)) ; no parent
(when (and (org-not-nil (org-entry-get (point) "ORDERED"))
(forward-line 1)
(re-search-forward org-not-done-heading-regexp pos t))
(setq org-block-entry-blocking (match-string 0))
(throw 'dont-block nil)) ; block, there is an older sibling not done.
;; Search further up the hierarchy, to see if an ancestor is blocked
(while t
(goto-char parent-pos)
(unless (looking-at org-not-done-heading-regexp)
(throw 'dont-block t)) ; do not block, parent is not a TODO
(setq pos (point))
(setq parent-pos (and (org-up-heading-safe) (point)))
(unless parent-pos (throw 'dont-block t)) ; no parent
(when (and (org-not-nil (org-entry-get (point) "ORDERED"))
(forward-line 1)
(re-search-forward org-not-done-heading-regexp pos t)
(setq org-block-entry-blocking (org-get-heading)))
(throw 'dont-block nil)))))))) ; block, older sibling not done.