Explorar o código

Checkboxes: Enforce sequential processing with ORDERED property

When the ORDERED property of an entry is set, checkboxes must be
completed in sequence.
Carsten Dominik %!s(int64=16) %!d(string=hai) anos
pai
achega
e6e3d97797
Modificáronse 7 ficheiros con 126 adicións e 12 borrados
  1. 27 0
      ORGWEBPAGE/Changes.org
  2. 7 0
      doc/ChangeLog
  3. 21 1
      doc/org.texi
  4. 2 1
      doc/orgcard.tex
  5. 9 0
      lisp/ChangeLog
  6. 26 1
      lisp/org-list.el
  7. 34 9
      lisp/org.el

+ 27 - 0
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
 A new index in the manual lists all variables mentioned in the
 manual, about 200.
 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
 * Version 6.22
 ** Details
 ** Details
 
 

+ 7 - 0
doc/ChangeLog

@@ -1,3 +1,10 @@
+2009-02-19  Carsten Dominik  <carsten.dominik@gmail.com>
+
+	* 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  <carsten.dominik@gmail.com>
 2009-02-18  Carsten Dominik  <carsten.dominik@gmail.com>
 
 
 	* org.texi (Global TODO list, Matching tags and properties):
 	* org.texi (Global TODO list, Matching tags and properties):

+ 21 - 1
doc/org.texi

@@ -3403,7 +3403,12 @@ example:
 @table @kbd
 @table @kbd
 @kindex C-c C-x o
 @kindex C-c C-x o
 @item 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
 @kindex C-u C-u C-u C-c C-t
 @item 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.
 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
 percentage of checkboxes checked (in the above example, this would be
 @samp{[50%]} and @samp{[33%]}, respectively).
 @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:
 @noindent The following commands work with checkboxes:
 
 
 @table @kbd
 @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.
 Insert a new item with a checkbox.
 This works only if the cursor is already in a plain list item
 This works only if the cursor is already in a plain list item
 (@pxref{Plain lists}).
 (@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 #
 @kindex C-c #
 @item C-c #
 @item C-c #
 Update the checkbox statistics in the current outline entry.  When
 Update the checkbox statistics in the current outline entry.  When

+ 2 - 1
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}
 \key{rotate the state of the current item}{C-c C-t}
 \metax{select next/previous state}{S-LEFT/RIGHT}
 \metax{select next/previous state}{S-LEFT/RIGHT}
 \metax{select next/previous set}{C-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 TODO items in a sparse tree}{C-c C-v}
 \key{view 3rd TODO keyword's sparse tree}{C-3 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{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(es) in region/entry/at point}{C-c C-x C-b}
 \key{toggle checkbox at point}{C-c C-c}
 \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 \#}
 \key{update checkbox statistics (\kbd{C-u} : whole file)}{C-c \#}
 
 
 \section{Tags}
 \section{Tags}

+ 9 - 0
lisp/ChangeLog

@@ -1,3 +1,12 @@
+2009-02-19  Carsten Dominik  <carsten.dominik@gmail.com>
+
+	* 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.el (org-modules): Add an entry for org-R.el.
 
 
 	* org-agenda.el (org-agenda-todo-ignore-with-date)
 	* org-agenda.el (org-agenda-todo-ignore-with-date)

+ 26 - 1
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."
 text below the heading."
   (interactive "P")
   (interactive "P")
   (catch 'exit
   (catch 'exit
-    (let (beg end status first-present first-status)
+    (let (beg end status first-present first-status blocked)
       (cond
       (cond
        ((org-region-active-p)
        ((org-region-active-p)
 	(setq beg (region-beginning) end (region-end)))
 	(setq beg (region-beginning) end (region-end)))
@@ -272,6 +272,9 @@ text below the heading."
 		(replace-match "")
 		(replace-match "")
 		(goto-char (match-beginning 0))
 		(goto-char (match-beginning 0))
 		(just-one-space))
 		(just-one-space))
+	    (when (setq blocked (org-checkbox-blocked-p))
+	      (error "Checkbox blocked because of unchecked box in line %d"
+		     blocked))
 	    (replace-match
 	    (replace-match
 	     (cond ((equal toggle-presence '(16)) "[-]")
 	     (cond ((equal toggle-presence '(16)) "[-]")
 		   ((member (match-string 0) '("[ ]" "[-]")) "[X]")
 		   ((member (match-string 0) '("[ ]" "[-]")) "[X]")
@@ -313,6 +316,28 @@ text below the heading."
 	  (beginning-of-line 2)))))
 	  (beginning-of-line 2)))))
   (org-update-checkbox-count-maybe))
   (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 ()
 (defun org-update-checkbox-count-maybe ()
   "Update checkbox statistics unless turned off by user."
   "Update checkbox statistics unless turned off by user."
   (when org-provide-checkbox-statistics
   (when org-provide-checkbox-statistics

+ 34 - 9
lisp/org.el

@@ -8707,17 +8707,42 @@ changes.  Such blocking occurs when:
 		    (throw 'dont-block nil)))))))
 		    (throw 'dont-block nil)))))))
     t))					; don't block
     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 ()
 (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)
   (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)
 (defun org-block-todo-from-checkboxes (change-plist)
   "Block turning an entry into a TODO, using checkboxes.
   "Block turning an entry into a TODO, using checkboxes.