diff --git a/.gitignore b/.gitignore index 6dc4d8a8e..4d7c503d8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,8 @@ tmp *~ .DS_Store +*# +.#* # # Local variables: diff --git a/ChangeLog b/ChangeLog index ebb2ec1d1..090f0f352 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ +2008-04-06 Carsten Dominik + + * lisp/org-agenda.el (org-agenda-start-with-clockreport-mode): New + option. + + * lisp/org-clock.el (org-dblock-write:clocktable): Request the + unrestricted list of files. + (org-get-clocktable): New function. + (org-dblock-write:clocktable): Make sure :tstart and :tend can not + only be strings but also integers (an absolute day number) and + lists (m d y). + 2008-04-04 Carsten Dominik + * lisp/org-agenda.el (org-agenda-clocktable-mode): New variable. + * doc/org.texi (Agenda commands): Document columns view in the agenda. diff --git a/ORGWEBPAGE/Changes.org b/ORGWEBPAGE/Changes.org index cfb683385..8449ada76 100644 --- a/ORGWEBPAGE/Changes.org +++ b/ORGWEBPAGE/Changes.org @@ -53,6 +53,14 @@ total time for each file will now also be listed. This was a request from Bernt Hansen. +*** Clockreport in the daily/weekly arenda + + If you turn on clockreport mode with the "R" key in the + agenda, a clock table will be attached to the agenda, showing + the clock report for the file scope and time interval of the + agenda view. To turn this on permanently, configure the + variable =org-agenda-start-with-clockreport-mode=. + *** Selective tag inheritance Inheritance of tags can now be limited to a subset of all diff --git a/doc/org.texi b/doc/org.texi index de2726b90..aec0e7055 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -5477,6 +5477,14 @@ previously used indirect buffer. Toggle Logbook mode. In Logbook mode, entries that where marked DONE while logging was on (variable @code{org-log-done}) are shown in the agenda, as are entries that have been clocked on that day. +@c +@kindex R +@item R +Toggle Clockreport mode. In clockreport mode, the daily/weekly agenda will +always show a table with the clocked times for the timespan and file scope +covered by the current agenda view. The initial setting for this mode in new +agenda buffers can be set with the variable +@code{org-agenda-start-with-follow-mode}. @tsubheading{Change display} @cindex display changing, in agenda diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index 9fd471d90..6048d16df 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -486,6 +486,11 @@ Needs to be set before org.el is loaded." :group 'org-agenda-startup :type 'boolean) +(defcustom org-agenda-start-with-clockreport-mode nil + "The initial value of clockreport-mode in a newly created agenda window." + :group 'org-agenda-startup + :type 'boolean) + (defgroup org-agenda-windows nil "Options concerning the windows used by the Agenda in Org Mode." :tag "Org Agenda Windows" @@ -922,6 +927,7 @@ works you probably want to add it to `org-agenda-custom-commands' for good." (defvar org-agenda-menu) ; defined later in this file. (defvar org-agenda-follow-mode nil) +(defvar org-agenda-clockreport-mode nil) (defvar org-agenda-show-log nil) (defvar org-agenda-redo-command nil) (defvar org-agenda-query-string nil) @@ -956,6 +962,7 @@ The following commands are available: buffer-substring-filters))) (unless org-agenda-keep-modes (setq org-agenda-follow-mode org-agenda-start-with-follow-mode + org-agenda-clockreport-mode org-agenda-start-with-clockreport-mode org-agenda-show-log nil)) (easy-menu-change '("Agenda") "Agenda Files" @@ -1016,6 +1023,7 @@ The following commands are available: (int-to-string (pop l)) 'digit-argument))) (org-defkey org-agenda-mode-map "f" 'org-agenda-follow-mode) +(org-defkey org-agenda-mode-map "R" 'org-agenda-clockreport-mode) (org-defkey org-agenda-mode-map "l" 'org-agenda-log-mode) (org-defkey org-agenda-mode-map "D" 'org-agenda-toggle-diary) (org-defkey org-agenda-mode-map "G" 'org-agenda-toggle-time-grid) @@ -1140,6 +1148,8 @@ The following commands are available: "--" ["Show Logbook entries" org-agenda-log-mode :style toggle :selected org-agenda-show-log :active (org-agenda-check-type nil 'agenda 'timeline)] + ["Show clock report" org-agenda-clockreport-mode + :style toggle :selected org-agenda-clockreport-mode :active (org-agenda-check-type nil 'agenda)] ["Include Diary" org-agenda-toggle-diary :style toggle :selected org-agenda-include-diary :active (org-agenda-check-type nil 'agenda)] ["Use Time Grid" org-agenda-toggle-time-grid @@ -2161,7 +2171,8 @@ given in `org-agenda-start-on-weekday'." (day-numbers (list start)) (day-cnt 0) (inhibit-redisplay (not debug-on-error)) - s e rtn rtnall file date d start-pos end-pos todayp nd) + s e rtn rtnall file date d start-pos end-pos todayp nd + clocktable-start clocktable-end) (setq org-agenda-redo-command (list 'org-agenda-list (list 'quote include-all) start-day ndays)) ;; Make the list of days @@ -2171,6 +2182,8 @@ given in `org-agenda-start-on-weekday'." (push (1+ (car day-numbers)) day-numbers) (setq ndays (1- ndays))) (setq day-numbers (nreverse day-numbers)) + (setq clocktable-start (car day-numbers) + clocktable-end (1+ (or (org-last day-numbers) 0))) (org-prepare-agenda "Day/Week") (org-set-local 'org-starting-day (car day-numbers)) (org-set-local 'org-include-all-loc include-all) @@ -2254,6 +2267,11 @@ given in `org-agenda-start-on-weekday'." "\n")) (put-text-property s (1- (point)) 'day d) (put-text-property s (1- (point)) 'org-day-cnt day-cnt)))) + (when (and org-agenda-clockreport-mode clocktable-start) + (let ((org-agenda-files (org-agenda-files))) + ;; the above line is to ensure the restricted range! + (insert (org-get-clocktable :tstart clocktable-start + :tend clocktable-end :link t)))) (goto-char (point-min)) (org-fit-agenda-window) (unless (and (pos-visible-in-window-p (point-min)) @@ -4102,6 +4120,16 @@ so that the date SD will be in that range." (message "Follow mode is %s" (if org-agenda-follow-mode "on" "off"))) +(defun org-agenda-clockreport-mode () + "Toggle clocktable mode in an agenda buffer." + (interactive) + (org-agenda-check-type t 'agenda) + (setq org-agenda-clockreport-mode (not org-agenda-clockreport-mode)) + (org-agenda-set-mode-name) + (org-agenda-redo) + (message "Clocktable mode is %s" + (if org-agenda-clockreport-mode "on" "off"))) + (defun org-agenda-log-mode () "Toggle log mode in an agenda buffer." (interactive) @@ -4141,7 +4169,8 @@ so that the date SD will be in that range." (if org-agenda-follow-mode " Follow" "") (if org-agenda-include-diary " Diary" "") (if org-agenda-use-time-grid " Grid" "") - (if org-agenda-show-log " Log" ""))) + (if org-agenda-show-log " Log" "") + (if org-agenda-clockreport-mode " Clock" ""))) (force-mode-line-update)) (defun org-agenda-post-command-hook () diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 4f3b7d6a7..33059e8c2 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -395,6 +395,29 @@ and is only done if the variable `org-clock-out-when-done' is not nil." (add-hook 'org-after-todo-state-change-hook 'org-clock-out-if-current) +;;;###autoload +(defun org-get-clocktable (&rest props) + "Get a formatted clocktable with parameters according to PROPS. +The table is created in a temporary buffer, fully formatted and +fontified, and then returned." + ;; Set the defaults + (setq props (plist-put props :name "clocktable")) + (unless (plist-member props :maxlevel) + (setq props (plist-put props :maxlevel 2))) + (unless (plist-member props :link) + (setq props (plist-put props :link nil))) + (unless (plist-member props :scope) + (setq props (plist-put props :scope 'agenda))) + (with-temp-buffer + (org-mode) + (org-create-dblock props) + (org-update-dblock) + (font-lock-fontify-buffer) + (forward-line 2) + (buffer-substring (point) (progn + (re-search-forward "^#\\+END" nil t) + (point-at-bol))))) + (defun org-clock-report (&optional arg) "Create a table containing a report about clocked time. If the cursor is inside an existing clocktable block, then the table @@ -557,7 +580,7 @@ the currently selected interval size." (catch 'exit (let* ((hlchars '((1 . "*") (2 . "/"))) (ins (make-marker)) - (total-time nil) + (total-time 0) (scope (plist-get params :scope)) (tostring (plist-get params :tostring)) (multifile (plist-get params :multifile)) @@ -577,6 +600,13 @@ the currently selected interval size." (when block (setq cc (org-clock-special-range block nil t) ts (car cc) te (nth 1 cc) range-text (nth 2 cc))) + (when (integerp ts) (setq ts (calendar-gregorian-from-absolute ts))) + (when (integerp te) (setq te (calendar-gregorian-from-absolute te))) + (when (and ts (listp ts)) + (setq ts (format "%4d-%02d-%02d" (nth 2 ts) (car ts) (nth 1 ts)))) + (when (and te (listp te)) + (setq te (format "%4d-%02d-%02d" (nth 2 te) (car te) (nth 1 te)))) + ;; Now the times are strings we can parse. (if ts (setq ts (time-to-seconds (apply 'encode-time (org-parse-time-string ts))))) (if te (setq te (time-to-seconds @@ -604,7 +634,7 @@ the currently selected interval size." (throw 'exit nil)))) (org-narrow-to-subtree)) ((or (listp scope) (eq scope 'agenda)) - (let* ((files (if (listp scope) scope (org-agenda-files))) + (let* ((files (if (listp scope) scope (org-agenda-files t))) (scope 'agenda) (p1 (copy-sequence params)) file) @@ -677,7 +707,7 @@ the currently selected interval size." (if (eq scope 'agenda) "|" "") "|" "*Total time*| *" - (org-minutes-to-hours total-time) + (org-minutes-to-hours (or total-time 0)) "*|\n|-\n") (setq tbl (delq nil tbl)) (if (and (stringp (car tbl)) (> (length (car tbl)) 1) diff --git a/lisp/org-macs.el b/lisp/org-macs.el index b8337db59..23122b0fe 100644 --- a/lisp/org-macs.el +++ b/lisp/org-macs.el @@ -27,12 +27,13 @@ ;; ;;; Commentary: -;; This file contains macro definitions, defsubst definitions, and -;; oder stuff needed for compilation and top-level forms in Org-mode. +;; This file contains macro definitions, defsubst definitions, other +;; stuff needed for compilation and top-level forms in Org-mode, as well +;; lots of small functions that are not org-mode specific but simply +;; generally useful stuff. ;;; Code: - (defmacro org-bound-and-true-p (var) "Return the value of symbol VAR if it is bound, else nil." `(and (boundp (quote ,var)) ,var)) @@ -212,6 +213,16 @@ we turn off invisibility temporarily. Use this in a `let' form." (goto-char (point-at-bol)) (looking-at re))) +(defun org-plist-delete (plist property) + "Delete PROPERTY from PLIST. +This is in contrast to merely setting it to 0." + (let (p) + (while plist + (if (not (eq property (car plist))) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p)) + (provide 'org-macs) ;;; org-macs.el ends here diff --git a/lisp/org.el b/lisp/org.el index 9ec28d35c..5828d1117 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -2831,7 +2831,8 @@ org-remember-apply-template org-remember org-remember-handler))) '(org-clock-in org-clock-out org-clock-cancel org-clock-goto org-clock-sum org-clock-display org-remove-clock-overlays org-clock-report - org-clocktable-shift org-dblock-write:clocktable))) + org-clocktable-shift org-dblock-write:clocktable + org-get-clocktable))) (defun org-clock-update-time-maybe () "If this is a CLOCK line, update it and return t. @@ -15120,3 +15121,12 @@ Still experimental, may disappear in the future." ;; arch-tag: e77da1a7-acc7-4336-b19e-efa25af3f9fd ;;; org.el ends here +(defun org-plist-delete (plist property) + "Delete PROPERTY from PLIST. +This is in contrast to merely setting it to 0." + (let (p) + (while plist + (if (not (eq property (car plist))) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p))