From a8ea078c33906001fce056aaba689fe564c7f829 Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Mon, 9 Nov 2009 17:22:58 +0100 Subject: [PATCH] Make it possible to record logbook entries when scheduling/deadlines change Rick Moynihan writes: > I'm wondering if anyone logs rescheduled tasks with org-mode... As I > find myself sometimes scheduling tasks for a future date, but then on > the day not having the capacity to do them. In these situations I > just reschedule them, but it'd be nice to record the dates for which > an item was originally scheduled in the LOGBOOK. > > Has anyone configured org-mode to do this? lognotedone only appears to > log state changes (rather than schedule/deadline changes). --- doc/ChangeLog | 7 ++++ doc/org.texi | 32 +++++++++++++---- lisp/ChangeLog | 12 +++++++ lisp/org.el | 111 ++++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 136 insertions(+), 26 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 50267459e..a85d26e49 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,10 @@ +2009-11-09 Carsten Dominik + + * org.texi (Inserting deadline/schedule): Document logging changes + of scheduling and deadline times stamps. + (In-buffer settings): Document the in-buffer keywords for logging + changes of scheduling and deadline times stamps. + 2009-11-03 Carsten Dominik * org.texi (Structure editing, Plain lists): Document indentation diff --git a/doc/org.texi b/doc/org.texi index 8e2225472..66cda81a6 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -5225,17 +5225,25 @@ an item: @c @kindex C-c C-d @item C-c C-d -Insert @samp{DEADLINE} keyword along with a stamp. The insertion will -happen in the line directly following the headline. When called with a -prefix arg, an existing deadline will be removed from the entry. +Insert @samp{DEADLINE} keyword along with a stamp. The insertion will happen +in the line directly following the headline. When called with a prefix arg, +an existing deadline will be removed from the entry. Depending on the +variable @code{org-log-redeadline}@footnote{with corresponding +@code{#+STARTUP} keyqwords @code{logredeadline}, @code{lognoteredeadline}, +and @code{nologredeadline}}, a note will be taken when changing an existing +deadline. @c FIXME Any CLOSED timestamp will be removed.???????? @c @kindex C-c C-s @item C-c C-s Insert @samp{SCHEDULED} keyword along with a stamp. The insertion will -happen in the line directly following the headline. Any CLOSED -timestamp will be removed. When called with a prefix argument, remove -the scheduling date from the entry. +happen in the line directly following the headline. Any CLOSED timestamp +will be removed. When called with a prefix argument, remove the scheduling +date from the entry. Depending on the variable +@code{org-log-reschedule}@footnote{with corresponding @code{#+STARTUP} +keywords @code{logredeadline}, @code{lognoteredeadline}, and +@code{nologredeadline}}, a note will be taken when changing an existing +scheduling time. @c @kindex C-c C-x C-k @kindex k a @@ -10505,6 +10513,12 @@ configured using these options (see variables @code{org-log-done}, @cindex @code{logrepeat}, STARTUP keyword @cindex @code{lognoterepeat}, STARTUP keyword @cindex @code{nologrepeat}, STARTUP keyword +@cindex @code{logreschedule}, STARTUP keyword +@cindex @code{lognotereschedule}, STARTUP keyword +@cindex @code{nologreschedule}, STARTUP keyword +@cindex @code{logredeadline}, STARTUP keyword +@cindex @code{lognoteredeadline}, STARTUP keyword +@cindex @code{nologredeadline}, STARTUP keyword @example logdone @r{record a timestamp when an item is marked DONE} lognotedone @r{record timestamp and a note when DONE} @@ -10514,6 +10528,12 @@ lognoterepeat @r{record a note when reinstating a repeating item} nologrepeat @r{do not record when reinstating repeating item} lognoteclock-out @r{record a note when clocking out} nolognoteclock-out @r{don't record a note when clocking out} +logreschedule @r{record a timestamp when scheduling time changes} +lognotereschedule @r{record a note when scheduling time changes} +nologreschedule @r{do not record when a scheduling date changes} +logredeadline @r{record a timestamp when deadline changes} +lognoteredeadline @r{record a note when deadline changes} +nologredeadline @r{do not record when a deadline date changes} @end example @vindex org-hide-leading-stars @vindex org-odd-levels-only diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 192f42b23..a41a995c5 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,15 @@ +2009-11-09 Carsten Dominik + + * org.el (org-log-reschedule, org-log-redeadline): New options. + (org-log-note-headings): Add templates for rescheduling and + deadline changing. + (org-startup-options): Add in-buffer settings for logging changing + schedule and deadline time stamps. + (org-deadline, org-schedule): Check for existing date and arrange + for logging if the user requests it. + (org-add-log-note): Prepare proper note buffers for rescheduling + and deadline changes. + 2009-11-08 Carsten Dominik * org-latex.el (org-export-latex-preprocess): Protect targets in diff --git a/lisp/org.el b/lisp/org.el index b3b8909b2..8f2bea78c 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -1951,7 +1951,7 @@ Possible values are: nil Don't add anything, just change the keyword time Add a time stamp to the task -note Prompt a closing note and add it with template `org-log-note-headings' +note Prompt for a note and add it with template `org-log-note-headings' This option can also be set with on a per-file-basis with @@ -1966,7 +1966,7 @@ property to one or more of these keywords." :type '(choice (const :tag "No logging" nil) (const :tag "Record CLOSED timestamp" time) - (const :tag "Record CLOSED timestamp with closing note." note))) + (const :tag "Record CLOSED timestamp with note." note))) ;; Normalize old uses of org-log-done. (cond @@ -1974,6 +1974,51 @@ property to one or more of these keywords." ((and (listp org-log-done) (memq 'done org-log-done)) (setq org-log-done 'note))) +(defcustom org-log-reschedule nil + "Information to record when the scheduling date of a tasks is modified. + +Possible values are: + +nil Don't add anything, just change the date +time Add a time stamp to the task +note Prompt for a note and add it with template `org-log-note-headings' + +This option can also be set with on a per-file-basis with + + #+STARTUP: nologreschedule + #+STARTUP: logreschedule + #+STARTUP: lognotereschedule" + :group 'org-todo + :group 'org-progress + :type '(choice + (const :tag "No logging" nil) + (const :tag "Record timestamp" time) + (const :tag "Record timestamp with note." note))) + +(defcustom org-log-redeadline nil + "Information to record when the deadline date of a tasks is modified. + +Possible values are: + +nil Don't add anything, just change the date +time Add a time stamp to the task +note Prompt for a note and add it with template `org-log-note-headings' + +This option can also be set with on a per-file-basis with + + #+STARTUP: nologredeadline + #+STARTUP: logredeadline + #+STARTUP: lognoteredeadline + +You can have local logging settings for a subtree by setting the LOGGING +property to one or more of these keywords." + :group 'org-todo + :group 'org-progress + :type '(choice + (const :tag "No logging" nil) + (const :tag "Record timestamp" time) + (const :tag "Record timestamp with note." note))) + (defcustom org-log-note-clock-out nil "Non-nil means, record a note when clocking out of an item. This can also be configured on a per-file basis by adding one of @@ -1995,6 +2040,8 @@ When nil, only the date will be recorded." '((done . "CLOSING NOTE %t") (state . "State %-12s from %-12S %t") (note . "Note taken on %t") + (reschedule . "Rescheduled from %S on %t") + (redeadline . "New deadline from %S on %t") (clock-out . "")) "Headings for notes added to entries. The value is an alist, with the car being a symbol indicating the note @@ -2013,7 +2060,9 @@ empty string. "Heading when changing todo state (todo sequence only)" state) string) (cons (const :tag "Heading when just taking a note" note) string) - (cons (const :tag "Heading when clocking out" clock-out) string))) + (cons (const :tag "Heading when clocking out" clock-out) string) + (cons (const :tag "Heading when rescheduling" reschedule) string) + (cons (const :tag "Heading when changing deadline" redeadline) string))) (unless (assq 'note org-log-note-headings) (push '(note . "%t") org-log-note-headings)) @@ -3630,6 +3679,12 @@ After a match, the following groups carry important information: ("logrepeat" org-log-repeat state) ("lognoterepeat" org-log-repeat note) ("nologrepeat" org-log-repeat nil) + ("logreschedule" org-log-reschedule time) + ("lognotereschedule" org-log-reschedule note) + ("nologreschedule" org-log-reschedule nil) + ("logredeadline" org-log-redeadline time) + ("lognoteredeadline" org-log-redeadline note) + ("nologredeadline" org-log-redeadline nil) ("fninline" org-footnote-define-inline t) ("nofninline" org-footnote-define-inline nil) ("fnlocal" org-footnote-section nil) @@ -10312,29 +10367,41 @@ With argument REMOVE, remove any deadline from the item. When TIME is set, it should be an internal time specification, and the scheduling will use the corresponding date." (interactive "P") - (if remove - (progn - (org-remove-timestamp-with-keyword org-deadline-string) - (message "Item no longer has a deadline.")) - (if (org-get-repeat) - (error "Cannot change deadline on task with repeater, please do that by hand") - (org-add-planning-info 'deadline time 'closed) - (message "Deadline on %s" org-last-inserted-timestamp)))) - + (let ((old-date (org-entry-get nil "DEADLINE"))) + (if remove + (progn + (org-remove-timestamp-with-keyword org-deadline-string) + (message "Item no longer has a deadline.")) + (if (org-get-repeat) + (error "Cannot change deadline on task with repeater, please do that by hand") + (org-add-planning-info 'deadline time 'closed) + (when (and old-date org-log-redeadline + (not (equal old-date + (substring org-last-inserted-timestamp 1 -1)))) + (org-add-log-setup 'redeadline nil old-date 'findpos + org-log-redeadline)) + (message "Deadline on %s" org-last-inserted-timestamp))))) + (defun org-schedule (&optional remove time) "Insert the SCHEDULED: string with a timestamp to schedule a TODO item. With argument REMOVE, remove any scheduling date from the item. When TIME is set, it should be an internal time specification, and the scheduling will use the corresponding date." (interactive "P") - (if remove - (progn - (org-remove-timestamp-with-keyword org-scheduled-string) - (message "Item is no longer scheduled.")) - (if (org-get-repeat) - (error "Cannot reschedule task with repeater, please do that by hand") - (org-add-planning-info 'scheduled time 'closed) - (message "Scheduled to %s" org-last-inserted-timestamp)))) + (let ((old-date (org-entry-get nil "SCHEDULED"))) + (if remove + (progn + (org-remove-timestamp-with-keyword org-scheduled-string) + (message "Item is no longer scheduled.")) + (if (org-get-repeat) + (error "Cannot reschedule task with repeater, please do that by hand") + (org-add-planning-info 'scheduled time 'closed) + (when (and old-date org-log-reschedule + (not (equal old-date + (substring org-last-inserted-timestamp 1 -1)))) + (org-add-log-setup 'reschedule nil old-date 'findpos + org-log-reschedule)) + (message "Scheduled to %s" org-last-inserted-timestamp))))) (defun org-get-scheduled-time (pom &optional inherit) "Get the scheduled time as a time tuple, of a format suitable @@ -10576,6 +10643,10 @@ EXTRA is additional text that will be inserted into the notes buffer." (format "state change from \"%s\" to \"%s\"" (or org-log-note-previous-state "") (or org-log-note-state ""))) + ((eq org-log-note-purpose 'reschedule) + "rescheduling") + ((eq org-log-note-purpose 'redeadline) + "changing deadline") ((eq org-log-note-purpose 'note) "this entry") (t (error "This should not happen"))))) -- 2.11.4.GIT