From e6e3d977975c3d276267a6b50ce8ee1955fa94eb Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Thu, 19 Feb 2009 09:13:08 +0100 Subject: [PATCH] Checkboxes: Enforce sequential processing with ORDERED property When the ORDERED property of an entry is set, checkboxes must be completed in sequence. --- ORGWEBPAGE/Changes.org | 27 ++++++++++++++++++++++++++ doc/ChangeLog | 7 +++++++ doc/org.texi | 22 ++++++++++++++++++++- doc/orgcard.tex | 3 ++- lisp/ChangeLog | 9 +++++++++ lisp/org-list.el | 27 +++++++++++++++++++++++++- lisp/org.el | 43 +++++++++++++++++++++++++++++++++--------- 7 files changed, 126 insertions(+), 12 deletions(-) diff --git a/ORGWEBPAGE/Changes.org b/ORGWEBPAGE/Changes.org index bcf3513fe..256ae0a60 100644 --- a/ORGWEBPAGE/Changes.org +++ b/ORGWEBPAGE/Changes.org @@ -107,6 +107,33 @@ Thanks to Richard Klinda for a patch to this effect. A new index in the manual lists all variables mentioned in the manual, about 200. +*** The ORDERED property also influences checkboxes + +When an entry has the ORDERED property set, checkboxes in +the entry must be completed in order. This was already the case +for children TODO items, now it also applies for checkboxes. + +Thanks to Rainer Stengele for this proposal. + +*** The ORDERED property can be tracked with a tag + +The =ORDERED= property is used to flag an entry so that subtasks +(both children TODO items and checkboxes) must be completed in +order. This property is most easily toggled with the command +=C-c C-x o=. A property was chosen for this functionality, +because this should be a behavior local to the current task, not +inherited like tags. However, properties are normally +invisible. If you would like visual feedback on the state of +this property, configure the variable +=org-track-ordered-property-with-tag=. If you then use =C-c C-x +o= to toggle the property, a tag will be toggled as well, for +visual feedback. + +Note that the tag itself has no meaning for the behavior of TODO +items and checkboxes, and that changing the tag with the usual +tag commands will not influence the property and therefore the +behavior of TODO and checkbox commands. + * Version 6.22 ** Details diff --git a/doc/ChangeLog b/doc/ChangeLog index 1fcca2b7c..74a62394f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,10 @@ +2009-02-19 Carsten Dominik + + * orgcard.tex: Document `C-c C-x o'. + + * org.texi (TODO dependencies, Checkboxes): Document + `org-track-ordered-property-with-tag'. + 2009-02-18 Carsten Dominik * org.texi (Global TODO list, Matching tags and properties): diff --git a/doc/org.texi b/doc/org.texi index 5a25ae4d6..f6dd023a1 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -3403,7 +3403,12 @@ example: @table @kbd @kindex C-c C-x o @item C-c C-x o -Toggle the @code{ORDERED} property of the current entry. +@vindex org-track-ordered-property-with-tag +Toggle the @code{ORDERED} property of the current entry. A property is used +for this behavior because this should be local to the current entry, not +inherited like a tag. However, if you would like to @i{track} the value of +this property with a tag for better visibility, customize the variable +@code{org-track-ordered-property-with-tag}. @kindex C-u C-u C-u C-c C-t @item C-u C-u C-u C-c C-t Change TODO state, circumventin any state blocking. @@ -3690,6 +3695,12 @@ the examples above. With @samp{[%]} you get information about the percentage of checkboxes checked (in the above example, this would be @samp{[50%]} and @samp{[33%]}, respectively). +@cindex blocking, of checkboxes +@cindex checkbox blocking +If the current outline node has an @code{ORDERED} property, checkboxes must +be checked off in sequence, and an error will be thrown if you try to check +off a box while there are unchecked boxes bove it. + @noindent The following commands work with checkboxes: @table @kbd @@ -3719,6 +3730,15 @@ If there is no active region, just toggle the checkbox at point. Insert a new item with a checkbox. This works only if the cursor is already in a plain list item (@pxref{Plain lists}). +@kindex C-c C-x o +@item C-c C-x o +@vindex org-track-ordered-property-with-tag +Toggle the @code{ORDERED} property of the entry, to toggle if checkboxes must +be checked off in sequence. A property is used for this behavior because +this should be local to the current entry, not inherited like a tag. +However, if you would like to @i{track} the value of this property with a tag +for better visibility, customize the variable +@code{org-track-ordered-property-with-tag}. @kindex C-c # @item C-c # Update the checkbox statistics in the current outline entry. When diff --git a/doc/orgcard.tex b/doc/orgcard.tex index 5bd65e002..53f4acc35 100644 --- a/doc/orgcard.tex +++ b/doc/orgcard.tex @@ -520,6 +520,7 @@ after ``{\tt :}'', and dictionary words elsewhere. \key{rotate the state of the current item}{C-c C-t} \metax{select next/previous state}{S-LEFT/RIGHT} \metax{select next/previous set}{C-S-LEFT/RIGHT} +\key{toggle ORDERED property}{C-c C-x o} \key{view TODO items in a sparse tree}{C-c C-v} \key{view 3rd TODO keyword's sparse tree}{C-3 C-c C-v} @@ -534,7 +535,7 @@ after ``{\tt :}'', and dictionary words elsewhere. \key{insert new checkbox item in plain list}{M-S-RET} \key{toggle checkbox(es) in region/entry/at point}{C-c C-x C-b} \key{toggle checkbox at point}{C-c C-c} -\metax{checkbox statistics cookies: insert {\tt [/]} or {\tt [\%]}}{} +%\metax{checkbox statistics cookies: insert {\tt [/]} or {\tt [\%]}}{} \key{update checkbox statistics (\kbd{C-u} : whole file)}{C-c \#} \section{Tags} diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d9f730b18..eedd85c8d 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2009-02-19 Carsten Dominik + + * org.el (org-track-ordered-property-with-tag): New option. + (org-toggle-ordered-property): Honor + `org-track-ordered-property-with-tag'. + + * org-list.el (org-checkbox-blocked-p): New function. + (org-toggle-checkbox): Check for blocking. + * org.el (org-modules): Add an entry for org-R.el. * org-agenda.el (org-agenda-todo-ignore-with-date) diff --git a/lisp/org-list.el b/lisp/org-list.el index 4be9c057f..6d8ee667b 100644 --- a/lisp/org-list.el +++ b/lisp/org-list.el @@ -259,7 +259,7 @@ If the cursor is in a headline, apply this to all checkbox items in the text below the heading." (interactive "P") (catch 'exit - (let (beg end status first-present first-status) + (let (beg end status first-present first-status blocked) (cond ((org-region-active-p) (setq beg (region-beginning) end (region-end))) @@ -272,6 +272,9 @@ text below the heading." (replace-match "") (goto-char (match-beginning 0)) (just-one-space)) + (when (setq blocked (org-checkbox-blocked-p)) + (error "Checkbox blocked because of unchecked box in line %d" + blocked)) (replace-match (cond ((equal toggle-presence '(16)) "[-]") ((member (match-string 0) '("[ ]" "[-]")) "[X]") @@ -313,6 +316,28 @@ text below the heading." (beginning-of-line 2))))) (org-update-checkbox-count-maybe)) +(defun org-checkbox-blocked-p () + "Is the current checkbox blocked from for being checked now? +A checkbox is blocked if all of the following conditions are fulfilled: + +1. The checkbox is not checked already. +2. The current entry has the ORDERED property set. +3. There is an unchecked checkbox in this entry before the current line." + (catch 'exit + (save-match-data + (save-excursion + (unless (org-at-item-checkbox-p) (throw 'exit nil)) + (when (equal (match-string 0) "[X]") + ;; the box is already checked! + (throw 'exit nil)) + (let ((end (point-at-bol))) + (condition-case nil (org-back-to-heading t) + (error (throw 'exit nil))) + (unless (org-entry-get nil "ORDERED") (throw 'exit nil)) + (if (re-search-forward "^[ \t]*[-+*0-9.)] \\[[- ]\\]" end t) + (org-current-line) + nil)))))) + (defun org-update-checkbox-count-maybe () "Update checkbox statistics unless turned off by user." (when org-provide-checkbox-statistics diff --git a/lisp/org.el b/lisp/org.el index 842c6d84f..ac998b44e 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -8707,17 +8707,42 @@ changes. Such blocking occurs when: (throw 'dont-block nil))))))) t)) ; don't block +(defcustom org-track-ordered-property-with-tag nil + "Should the ORDERED property also be shown as a tag? +The ORDERED property decides if an entry should require subtasks to be +completed in sequence. Since a property is not very visible, setting +this option means that toggling the ORDERED property with the command +`org-toggle-ordered-property' will also toggle a tag ORDERED. That tag is +not relevant for the behavior, but it makes things more visible. + +Note that toggling the tag with tags commands will not change the property +and therefore not influence behavior! + +This can be t, meaning the tag ORDERED should be used, It can also be a +string to select a different tag for this task." + :group 'org-todo + :type '(choice + (const :tag "No tracking" nil) + (const :tag "Track with ORDERED tag" t) + (string :tag "Use other tag"))) + (defun org-toggle-ordered-property () - "Toggle the ORDERED property of the current entry." + "Toggle the ORDERED property of the current entry. +For better visibility, you can track the value of this property with a tag. +See variable `org-track-ordered-property-with-tag'." (interactive) - (save-excursion - (org-back-to-heading) - (if (org-entry-get nil "ORDERED") - (progn - (org-delete-property "ORDERED") - (message "Subtasks can be completed in arbitrary order or parallel")) - (org-entry-put nil "ORDERED" "t") - (message "Subtasks must be completed in sequence")))) + (let* ((t1 org-track-ordered-property-with-tag) + (tag (and t1 (if (stringp t1) t1 "ORDERED")))) + (save-excursion + (org-back-to-heading) + (if (org-entry-get nil "ORDERED") + (progn + (org-delete-property "ORDERED") + (and tag (org-toggle-tag tag 'off)) + (message "Subtasks can be completed in arbitrary order")) + (org-entry-put nil "ORDERED" "t") + (and tag (org-toggle-tag tag 'on)) + (message "Subtasks must be completed in sequence"))))) (defun org-block-todo-from-checkboxes (change-plist) "Block turning an entry into a TODO, using checkboxes.