;;; org-clock.el --- The time clocking code for Org-mode
-;; Copyright (C) 2004-2011 Free Software Foundation, Inc.
+;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
;; Homepage: http://orgmode.org
-;; Version: 7.4
;;
;; This file is part of GNU Emacs.
;;
;; This file contains the time clocking code for Org-mode
(require 'org)
+(require 'org-exp)
;;; Code:
(eval-when-compile
(declare-function calendar-absolute-from-iso "cal-iso" (&optional date))
(declare-function notifications-notify "notifications" (&rest params))
+(declare-function org-pop-to-buffer-same-window "org-compat" (&optional buffer-or-name norecord label))
(defvar org-time-stamp-formats)
+(defvar org-ts-what)
(defgroup org-clock nil
"Options concerning clocking working time in Org-mode."
(const :tag "Into LOGBOOK drawer" "LOGBOOK")
(string :tag "Into Drawer named...")))
+(defun org-clock-into-drawer ()
+ "Return the value of `org-clock-into-drawer', but let properties overrule.
+If the current entry has or inherits a CLOCK_INTO_DRAWER
+property, it will be used instead of the default value; otherwise
+if the current entry has or inherits a LOG_INTO_DRAWER property,
+it will be used instead of the default value.
+The default is the value of the customizable variable `org-clock-into-drawer',
+which see."
+ (let ((p (org-entry-get nil "CLOCK_INTO_DRAWER" 'inherit))
+ (q (org-entry-get nil "LOG_INTO_DRAWER" 'inherit)))
+ (cond
+ ((or (not (or p q)) (equal p "nil") (equal q "nil")) org-clock-into-drawer)
+ ((or (equal p "t") (equal q "t")) "LOGBOOK")
+ ((not p) q)
+ (t p))))
+
(defcustom org-clock-out-when-done t
"When non-nil, clock will be stopped when the clocked entry is marked DONE.
DONE here means any DONE-like state.
:type 'function)
(defcustom org-clock-string-limit 0
- "Maximum length of clock strings in the modeline. 0 means no limit."
+ "Maximum length of clock strings in the mode line. 0 means no limit."
:group 'org-clock
:type 'integer)
(file :tag "Play sound file")))
(defcustom org-clock-modeline-total 'auto
- "Default setting for the time included for the modeline clock.
+ "Default setting for the time included for the mode line clock.
This can be overruled locally using the CLOCK_MODELINE_TOTAL property.
Allowed values are:
(const :tag "All task time" all)
(const :tag "Automatically, `all' or since `repeat'" auto)))
-(defcustom org-task-overrun-text nil
- "The extra modeline text that should indicate that the clock is overrun.
+(defvaralias 'org-task-overrun-text 'org-clock-task-overrun-text)
+(defcustom org-clock-task-overrun-text nil
+ "Extra mode line text to indicate that the clock is overrun.
The can be nil to indicate that instead of adding text, the clock time
should get a different face (`org-mode-line-clock-overrun').
When this is a string, it is prepended to the clock string as an indication,
also using the face `org-mode-line-clock-overrun'."
:group 'org-clock
+ :version "24.1"
:type '(choice
(const :tag "Just mark the time string" nil)
(string :tag "Text to prepend")))
:group 'org-clock)
(defcustom org-clocktable-defaults
- (list
- :maxlevel 2
- :scope 'file
- :block nil
- :tstart nil
- :tend nil
- :step nil
- :stepskip0 nil
- :fileskip0 nil
- :tags nil
- :emphasize nil
- :link nil
- :narrow '40!
- :indent t
- :formula nil
- :timestamp nil
- :level nil
- :tcolumns nil
- :formatter nil)
+ `(list
+ :maxlevel 2
+ :lang ,org-export-default-language
+ :scope 'file
+ :block nil
+ :tstart nil
+ :tend nil
+ :step nil
+ :stepskip0 nil
+ :fileskip0 nil
+ :tags nil
+ :emphasize nil
+ :link nil
+ :narrow '40!
+ :indent t
+ :formula nil
+ :timestamp nil
+ :level nil
+ :tcolumns nil
+ :formatter nil)
"Default properties for clock tables."
:group 'org-clock
+ :version "24.1"
:type 'plist)
(defcustom org-clock-clocktable-formatter 'org-clocktable-write-default
"Function to turn clocking data into a table.
For more information, see `org-clocktable-write-default'."
:group 'org-clocktable
+ :version "24.1"
:type 'function)
+;; FIXME: translate es and nl last string "Clock summary at"
+(defcustom org-clock-clocktable-language-setup
+ '(("en" "File" "L" "Timestamp" "Headline" "Time" "ALL" "Total time" "File time" "Clock summary at")
+ ("es" "Archivo" "N" "Fecha y hora" "Tarea" "Tiempo" "TODO" "Tiempo total" "Tiempo archivo" "Clock summary at")
+ ("fr" "Fichier" "N" "Horodatage" "En-tête" "Durée" "TOUT" "Durée totale" "Durée fichier" "Horodatage sommaire à")
+ ("nl" "Bestand" "N" "Tijdstip" "Hoofding" "Duur" "ALLES" "Totale duur" "Bestandstijd" "Clock summary at"))
+ "Terms used in clocktable, translated to different languages."
+ :group 'org-clocktable
+ :version "24.1"
+ :type 'alist)
+
(defcustom org-clock-clocktable-default-properties '(:maxlevel 2 :scope file)
"Default properties for new clocktables.
These will be inserted into the BEGIN line, to make it easy for users to
(defcustom org-clock-report-include-clocking-task nil
"When non-nil, include the current clocking task time in clock reports."
:group 'org-clock
+ :version "24.1"
:type 'boolean)
(defcustom org-clock-resolve-expert nil
"Non-nil means do not show the splash buffer with the clock resolver."
:group 'org-clock
+ :version "24.1"
:type 'boolean)
(defvar org-clock-in-prepare-hook nil
"Return t when clocking a task."
(not (equal (org-clocking-buffer) nil)))
+(defvar org-clock-before-select-task-hook nil
+ "Hook called in task selection just before prompting the user.")
+
(defun org-clock-select-task (&optional prompt)
"Select a task that recently was associated with clocking."
(interactive)
(if (fboundp 'int-to-char) (setf (car s) (int-to-char (car s))))
(push s sel-list)))
org-clock-history)
+ (run-hooks 'org-clock-before-select-task-hook)
(org-fit-window-to-buffer)
(message (or prompt "Select task for clocking:"))
(setq rpl (read-char-exclusive))
(ignore-errors
(goto-char marker)
(setq file (buffer-file-name (marker-buffer marker))
- cat (or (org-get-category)
- (progn (org-refresh-category-properties)
- (org-get-category)))
+ cat (org-get-category)
heading (org-get-heading 'notags)
prefix (save-excursion
(org-back-to-heading t)
- (looking-at "\\*+ ")
+ (looking-at org-outline-regexp)
(match-string 0))
task (substring
(org-fontify-like-in-org-mode
(insert (format "[%c] %-15s %s\n" i cat task))
(cons i marker)))))
-(defvar org-task-overrun nil
+(defvar org-clock-task-overrun nil
"Internal flag indicating if the clock has overrun the planned time.")
(defvar org-clock-update-period 60
"Number of seconds between mode line clock string updates.")
(m (- clocked-time (* 60 h))))
(if org-clock-effort
(let* ((effort-in-minutes
- (org-hh:mm-string-to-minutes org-clock-effort))
+ (org-duration-string-to-minutes org-clock-effort))
(effort-h (floor effort-in-minutes 60))
(effort-m (- effort-in-minutes (* effort-h 60)))
(work-done-str
(org-propertize
(format org-time-clocksum-format h m)
- 'face (if (and org-task-overrun (not org-task-overrun-text))
+ 'face (if (and org-clock-task-overrun (not org-clock-task-overrun-text))
'org-mode-line-clock-overrun 'org-mode-line-clock)))
(effort-str (format org-time-clocksum-format effort-h effort-m))
(clockstr (org-propertize
(defun org-clock-update-mode-line ()
(if org-clock-effort
(org-clock-notify-once-if-expired)
- (setq org-task-overrun nil))
+ (setq org-clock-task-overrun nil))
(setq org-mode-line-string
(org-propertize
(let ((clock-string (org-clock-get-clock-string))
'local-map org-clock-mode-line-map
'mouse-face (if (featurep 'xemacs) 'highlight 'mode-line-highlight)
))
- (if (and org-task-overrun org-task-overrun-text)
+ (if (and org-clock-task-overrun org-clock-task-overrun-text)
(setq org-mode-line-string
(concat (org-propertize
- org-task-overrun-text
+ org-clock-task-overrun-text
'face 'org-mode-line-clock-overrun) org-mode-line-string)))
(force-mode-line-update))
;; A string. See if it is a delta
(setq sign (string-to-char value))
(if (member sign '(?- ?+))
- (setq current (org-hh:mm-string-to-minutes current)
+ (setq current (org-duration-string-to-minutes current)
value (substring value 1))
(setq current 0))
- (setq value (org-hh:mm-string-to-minutes value))
+ (setq value (org-duration-string-to-minutes value))
(if (equal ?- sign)
(setq value (- current value))
(if (equal ?+ sign) (setq value (+ current value)))))
"Show notification if we spent more time than we estimated before.
Notification is shown only once."
(when (org-clocking-p)
- (let ((effort-in-minutes (org-hh:mm-string-to-minutes org-clock-effort))
+ (let ((effort-in-minutes (org-duration-string-to-minutes org-clock-effort))
(clocked-time (org-clock-get-clocked-time)))
- (if (setq org-task-overrun
+ (if (setq org-clock-task-overrun
(if (or (null effort-in-minutes) (zerop effort-in-minutes))
nil
(>= clocked-time effort-in-minutes)))
(error (beep t) (beep t)))))))))
(defun org-program-exists (program-name)
- "Checks whenever we can locate program and launch it."
- (if (eq system-type 'gnu/linux)
+ "Checks whenever we can locate PROGRAM-NAME using the `which' executable."
+ (if (member system-type '(gnu/linux darwin))
(= 0 (call-process "which" nil nil nil program-name))))
(defvar org-clock-mode-line-entry nil
- "Information for the modeline about the running clock.")
+ "Information for the mode line about the running clock.")
(defun org-find-open-clocks (file)
"Search through the given file and find all open clocks."
(goto-char (car ,clock))
(beginning-of-line)
,@forms))))
-
+(def-edebug-spec org-with-clock-position (form body))
(put 'org-with-clock-position 'lisp-indent-function 1)
(defmacro org-with-clock (clock &rest forms)
(outline-back-to-heading t)
(point-marker))))
,@forms)))
-
+(def-edebug-spec org-with-clock (form body))
(put 'org-with-clock 'lisp-indent-function 1)
(defsubst org-clock-clock-in (clock &optional resume start-time)
(defun org-clock-jump-to-current-clock (&optional effective-clock)
(interactive)
- (let ((clock (or effective-clock (cons org-clock-marker
+ (let ((org-clock-into-drawer (org-clock-into-drawer))
+ (clock (or effective-clock (cons org-clock-marker
org-clock-start-time))))
(unless (marker-buffer (car clock))
(error "No clock is currently running"))
60.0))))
org-clock-user-idle-start)))))
+(defvar org-clock-current-task nil
+ "Task currently clocked in.")
+(defun org-clock-set-current ()
+ "Set `org-clock-current-task' to the task currently clocked in."
+ (setq org-clock-current-task (nth 4 (org-heading-components))))
+
+(defun org-clock-delete-current ()
+ "Reset `org-clock-current-task' to nil."
+ (setq org-clock-current-task nil))
+
(defun org-clock-in (&optional select start-time)
"Start the clock on the current item.
If necessary, clock-out of the currently active clock.
ts selected-task target-pos (msg-extra "")
(leftover (and (not org-clock-resolving-clocks)
org-clock-leftover-time)))
+
(when (and org-clock-auto-clock-resolution
(or (not interrupting)
(eq t org-clock-auto-clock-resolution))
(setq org-clock-leftover-time nil)
(let ((org-clock-clocking-in t))
(org-resolve-clocks))) ; check if any clocks are dangling
+
(when (equal select '(4))
(setq selected-task (org-clock-select-task "Clock-in on task: "))
(if selected-task
(setq selected-task (copy-marker selected-task))
(error "Abort")))
+
+ (when (equal select '(16))
+ ;; Mark as default clocking task
+ (org-clock-mark-default-task))
+
(when interrupting
;; We are interrupting the clocking of a different task.
;; Save a marker to this task, so that we can go back.
(= (marker-position org-clock-hd-marker)
(if selected-task
(marker-position selected-task)
- (point)))))
+ (point)))
+ (equal org-clock-current-task (nth 4 (org-heading-components)))))
(message "Clock continues in \"%s\"" org-clock-heading)
(throw 'abort nil))
(move-marker org-clock-interrupted-task
(let ((org-clock-clocking-in t))
(org-clock-out t)))
- (when (equal select '(16))
- ;; Mark as default clocking task
- (org-clock-mark-default-task))
-
;; Clock in at which position?
(setq target-pos
- (if (and (eobp) (not (org-on-heading-p)))
+ (if (and (eobp) (not (org-at-heading-p)))
(point-at-bol 0)
(point)))
(run-hooks 'org-clock-in-prepare-hook)
(match-string 2))))
(if newstate (org-todo newstate))))
((and org-clock-in-switch-to-state
- (not (looking-at (concat outline-regexp "[ \t]*"
+ (not (looking-at (concat org-outline-regexp "[ \t]*"
org-clock-in-switch-to-state
"\\>"))))
(org-todo org-clock-in-switch-to-state)))
(cond
((and org-clock-in-resume
(looking-at
- (concat "^[ \t]* " org-clock-string
+ (concat "^[ \t]*" org-clock-string
" \\[\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}"
- " +\\sw+\.? +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")))
+ " *\\sw+\.? +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")))
(message "Matched %s" (match-string 1))
(setq ts (concat "[" (match-string 1) "]"))
(goto-char (match-end 1))
(message "Clock starts at %s - %s" ts msg-extra)
(run-hooks 'org-clock-in-hook)))))))
-(defvar org-clock-current-task nil
- "Task currently clocked in.")
-(defun org-clock-set-current ()
- "Set `org-clock-current-task' to the task currently clocked in."
- (setq org-clock-current-task (nth 4 (org-heading-components))))
-
-(defun org-clock-delete-current ()
- "Reset `org-clock-current-task' to nil."
- (setq org-clock-current-task nil))
-
(defun org-clock-mark-default-task ()
"Mark current task as default task."
(interactive)
line and position cursor in that line."
(org-back-to-heading t)
(catch 'exit
- (let ((beg (save-excursion
- (beginning-of-line 2)
- (or (bolp) (newline))
- (point)))
- (end (progn (outline-next-heading) (point)))
- (re (concat "^[ \t]*" org-clock-string))
- (cnt 0)
- (drawer (if (stringp org-clock-into-drawer)
- org-clock-into-drawer "LOGBOOK"))
- first last ind-last)
+ (let* ((org-clock-into-drawer (org-clock-into-drawer))
+ (beg (save-excursion
+ (beginning-of-line 2)
+ (or (bolp) (newline))
+ (point)))
+ (end (progn (outline-next-heading) (point)))
+ (re (concat "^[ \t]*" org-clock-string))
+ (cnt 0)
+ (drawer (if (stringp org-clock-into-drawer)
+ org-clock-into-drawer "LOGBOOK"))
+ first last ind-last)
(goto-char beg)
(when (and find-unclosed
(re-search-forward
- (concat "^[ \t]* " org-clock-string
+ (concat "^[ \t]*" org-clock-string
" \\[\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}"
- " +\\sw+ +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")
+ " *\\sw+ +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")
end t))
(beginning-of-line 1)
(throw 'exit t))
(beginning-of-line 2)
(if (and (>= (org-get-indentation) ind-last)
(org-at-item-p))
- (org-end-of-item))
+ (when (and (>= (org-get-indentation) ind-last)
+ (org-at-item-p))
+ (let ((struct (org-list-struct)))
+ (goto-char (org-list-get-bottom-point struct)))))
(insert ":END:\n")
(beginning-of-line 0)
(org-indent-line-to ind-last)
(match-string 2))))
(if newstate (org-todo newstate))))
((and org-clock-out-switch-to-state
- (not (looking-at (concat outline-regexp "[ \t]*"
+ (not (looking-at (concat org-outline-regexp "[ \t]*"
org-clock-out-switch-to-state
"\\>"))))
(org-todo org-clock-out-switch-to-state))))))
(run-hooks 'org-clock-out-hook)
(org-clock-delete-current))))))
+(add-hook 'org-clock-out-hook 'org-clock-remove-empty-clock-drawer)
+
+(defun org-clock-remove-empty-clock-drawer nil
+ "Remove empty clock drawer in the current subtree."
+ (let* ((olid (or (org-entry-get (point) "LOG_INTO_DRAWER")
+ org-log-into-drawer))
+ (clock-drawer (if (eq t olid) "LOGBOOK" olid))
+ (end (save-excursion (org-end-of-subtree t t))))
+ (when clock-drawer
+ (save-excursion
+ (org-back-to-heading t)
+ (while (search-forward clock-drawer end t)
+ (goto-char (match-beginning 0))
+ (org-remove-empty-drawer-at clock-drawer (point))
+ (forward-line 1))))))
+
+(defun org-at-clock-log-p nil
+ "Is the cursor on the clock log line?"
+ (save-excursion
+ (move-beginning-of-line 1)
+ (looking-at "^[ \t]*CLOCK:")))
+
+(defun org-clock-timestamps-up nil
+ "Increase CLOCK timestamps at cursor."
+ (interactive)
+ (org-clock-timestamps-change 'up))
+
+(defun org-clock-timestamps-down nil
+ "Increase CLOCK timestamps at cursor."
+ (interactive)
+ (org-clock-timestamps-change 'down))
+
+(defun org-clock-timestamps-change (updown)
+ "Change CLOCK timestamps synchronously at cursor.
+UPDOWN tells whether to change 'up or 'down."
+ (setq org-ts-what nil)
+ (when (org-at-timestamp-p t)
+ (let ((tschange (if (eq updown 'up) 'org-timestamp-up
+ 'org-timestamp-down))
+ ts1 begts1 ts2 begts2 updatets1 tdiff)
+ (save-excursion
+ (move-beginning-of-line 1)
+ (re-search-forward org-ts-regexp3 nil t)
+ (setq ts1 (match-string 0) begts1 (match-beginning 0))
+ (when (re-search-forward org-ts-regexp3 nil t)
+ (setq ts2 (match-string 0) begts2 (match-beginning 0))))
+ ;; Are we on the second timestamp?
+ (if (<= begts2 (point)) (setq updatets1 t))
+ (if (not ts2)
+ ;; fall back on org-timestamp-up if there is only one
+ (funcall tschange)
+ ;; setq this so that (boundp 'org-ts-what is non-nil)
+ (funcall tschange)
+ (let ((ts (if updatets1 ts2 ts1))
+ (begts (if updatets1 begts1 begts2)))
+ (setq tdiff
+ (subtract-time
+ (org-time-string-to-time org-last-changed-timestamp)
+ (org-time-string-to-time ts)))
+ (save-excursion
+ (goto-char begts)
+ (org-timestamp-change
+ (round (/ (org-float-time tdiff)
+ (cond ((eq org-ts-what 'minute) 60)
+ ((eq org-ts-what 'hour) 3600)
+ ((eq org-ts-what 'day) (* 24 3600))
+ ((eq org-ts-what 'month) (* 24 3600 31))
+ ((eq org-ts-what 'year) (* 24 3600 365.2)))))
+ org-ts-what 'updown)))))))
+
(defun org-clock-cancel ()
"Cancel the running clock by removing the start timestamp."
(interactive)
(setq recent t)
(car org-clock-history))
(t (error "No active or recent clock task")))))
- (switch-to-buffer (marker-buffer m))
+ (org-pop-to-buffer-same-window (marker-buffer m))
(if (or (< m (point-min)) (> m (point-max))) (widen))
(goto-char m)
(org-show-entry)
(defun org-clock-display (&optional total-only)
"Show subtree times in the entire buffer.
If TOTAL-ONLY is non-nil, only show the total time for the entire file
-in the echo area."
+in the echo area.
+
+Use \\[org-clock-remove-overlays] to remove the subtree times."
(interactive)
(org-clock-remove-overlays)
(let (time h m p)
(remove-hook 'before-change-functions
'org-clock-remove-overlays 'local))))
-(defvar state) ;; dynamically scoped into this function
+(defvar org-state) ;; dynamically scoped into this function
(defun org-clock-out-if-current ()
"Clock out if the current entry contains the running clock.
This is used to stop the clock after a TODO entry is marked DONE,
and is only done if the variable `org-clock-out-when-done' is not nil."
- (when (and org-clock-out-when-done
+ (when (and (org-clocking-p)
+ org-clock-out-when-done
+ (marker-buffer org-clock-marker)
(or (and (eq t org-clock-out-when-done)
- (member state org-done-keywords))
+ (member org-state org-done-keywords))
(and (listp org-clock-out-when-done)
- (member state org-clock-out-when-done)))
+ (member org-state org-clock-out-when-done)))
(equal (or (buffer-base-buffer (org-clocking-buffer))
(org-clocking-buffer))
(or (buffer-base-buffer (current-buffer))
(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
-will be updated. If not, a new clocktable will be inserted.
+will be updated. If not, a new clocktable will be inserted. The scope
+of the new clock will be subtree when called from within a subtree, and
+file elsewhere.
+
When called with a prefix argument, move to the first clock table in the
buffer and update it."
(interactive "P")
(org-show-entry))
(if (org-in-clocktable-p)
(goto-char (org-in-clocktable-p))
- (org-create-dblock (append (list :name "clocktable")
- org-clock-clocktable-default-properties)))
+ (let ((props (if (ignore-errors
+ (save-excursion (org-back-to-heading)))
+ (list :name "clocktable" :scope 'subtree)
+ (list :name "clocktable"))))
+ (org-create-dblock
+ (org-combine-plists org-clock-clocktable-default-properties props))))
(org-update-dblock))
-(defun org-in-clocktable-p ()
- "Check if the cursor is in a clocktable."
- (let ((pos (point)) start)
- (save-excursion
- (end-of-line 1)
- (and (re-search-backward "^[ \t]*#\\+BEGIN:[ \t]+clocktable" nil t)
- (setq start (match-beginning 0))
- (re-search-forward "^[ \t]*#\\+END:.*" nil t)
- (>= (match-end 0) pos)
- start))))
-
(defun org-day-of-week (day month year)
"Returns the day of the week as an integer."
(nth 6
shiftedm (- 13 (* 3 (nth 1 tmp)))
shiftedq (- 5 (nth 1 tmp))))
(setq d 1 h 0 m 0 d1 1 month shiftedm month1 (+ 3 shiftedm) h1 0 m1 0 y shiftedy))
- ((> (+ q shift) 0) ; shift is whitin this year
+ ((> (+ q shift) 0) ; shift is within this year
(setq shiftedq (+ q shift))
(setq shiftedy y)
(setq d 1 h 0 m 0 d1 1 month (+ 1 (* 3 (- (+ q shift) 1))) month1 (+ 4 (* 3 (- (+ q shift) 1))) h1 0 m1 0))))
(encode-time 0 0 0 (+ d n) m y))))
((and wp (string-match "w\\|W" wp) mw (> (length wp) 0))
(require 'cal-iso)
- (setq date (calendar-gregorian-from-absolute (calendar-absolute-from-iso (list (+ mw n) 1 y))))
+ (setq date (calendar-gregorian-from-absolute
+ (calendar-absolute-from-iso (list (+ mw n) 1 y))))
(setq ins (format-time-string
"%G-W%V"
(encode-time 0 0 0 (nth 1 date) (car date) (nth 2 date)))))
(setq mw 5
y (- y 1))
())
- (setq date (calendar-gregorian-from-absolute (calendar-absolute-from-iso (org-quarter-to-date (+ mw n) y))))
+ (setq date (calendar-gregorian-from-absolute
+ (calendar-absolute-from-iso (org-quarter-to-date (+ mw n) y))))
(setq ins (format-time-string
(concatenate 'string (number-to-string y) "-Q" (number-to-string (+ mw n)))
(encode-time 0 0 0 (nth 1 date) (car date) (nth 2 date)))))
'org-clocktable-write-default))
cc range-text ipos pos one-file-with-archives
scope-is-list tbls level)
-
;; Check if we need to do steps
(when block
;; Get the range text for the header
(setq level (string-to-number (match-string 1 (symbol-name scope))))
(catch 'exit
(while (org-up-heading-safe)
- (looking-at outline-regexp)
+ (looking-at org-outline-regexp)
(if (<= (org-reduced-level (funcall outline-level)) level)
(throw 'exit nil))))
(org-narrow-to-subtree)))
"Write out a clock table at position IPOS in the current buffer.
TABLES is a list of tables with clocking data as produced by
`org-clock-get-table-data'. PARAMS is the parameter property list obtained
-from the dynamic block defintion."
- ;; This function looks quite complicated, mainly because there are a lot
- ;; of options which can add or remove columns. I have massively commented
- ;; function, to I hope it is understandable. If someone want to write
- ;; there own special formatter, this maybe much easier because there can
- ;; be a fixed format with a well-defined number of columns...
+from the dynamic block definition."
+ ;; This function looks quite complicated, mainly because there are a
+ ;; lot of options which can add or remove columns. I have massively
+ ;; commented this function, the I hope it is understandable. If
+ ;; someone wants to write their own special formatter, this maybe
+ ;; much easier because there can be a fixed format with a
+ ;; well-defined number of columns...
(let* ((hlchars '((1 . "*") (2 . "/")))
+ (lwords (assoc (or (plist-get params :lang)
+ org-export-default-language)
+ org-clock-clocktable-language-setup))
(multifile (plist-get params :multifile))
(block (plist-get params :block))
(ts (plist-get params :tstart))
(emph (plist-get params :emphasize))
(level-p (plist-get params :level))
(timestamp (plist-get params :timestamp))
+ (properties (plist-get params :properties))
(ntcol (max 1 (or (plist-get params :tcolumns) 100)))
(rm-file-column (plist-get params :one-file-with-archives))
(indent (plist-get params :indent))
(or header
;; Format the standard header
(concat
- "Clock summary at ["
+ (nth 9 lwords) " ["
(substring
(format-time-string (cdr org-time-stamp-formats))
1 -1)
(if multifile "|" "") ; file column, maybe
(if level-p "|" "") ; level column, maybe
(if timestamp "|" "") ; timestamp column, maybe
+ (if properties (make-string (length properties) ?|) "") ;properties columns, maybe
(format "<%d>| |\n" narrow))) ; headline and time columns
;; Insert the table header line
(insert-before-markers
"|" ; table line starter
- (if multifile "File|" "") ; file column, maybe
- (if level-p "L|" "") ; level column, maybe
- (if timestamp "Timestamp|" "") ; timestamp column, maybe
- "Headline|Time|\n") ; headline and time columns
+ (if multifile (concat (nth 1 lwords) "|") "") ; file column, maybe
+ (if level-p (concat (nth 2 lwords) "|") "") ; level column, maybe
+ (if timestamp (concat (nth 3 lwords) "|") "") ; timestamp column, maybe
+ (if properties (concat (mapconcat 'identity properties "|") "|") "") ;properties columns, maybe
+ (concat (nth 4 lwords) "|"
+ (nth 5 lwords) "|\n")) ; headline and time columns
;; Insert the total time in the table
(insert-before-markers
- "|-\n" ; a hline
- "|" ; table line starter
- (if multifile "| ALL " "") ; file column, maybe
- (if level-p "|" "") ; level column, maybe
- (if timestamp "|" "") ; timestamp column, maybe
- "*Total time*| " ; instead of a headline
+ "|-\n" ; a hline
+ "|" ; table line starter
+ (if multifile (concat "| " (nth 6 lwords) " ") "")
+ ; file column, maybe
+ (if level-p "|" "") ; level column, maybe
+ (if timestamp "|" "") ; timestamp column, maybe
+ (if properties (make-string (length properties) ?|) "") ;properties columns, maybe
+ (concat "*" (nth 7 lwords) "*| ") ; instead of a headline
"*"
(org-minutes-to-hh:mm-string (or total-time 0)) ; the time
"*|\n") ; close line
(insert-before-markers "|-\n") ; a hline because a new file starts
;; First the file time, if we have multiple files
(when multifile
- ;; Summarize the time colleted from this file
+ ;; Summarize the time collected from this file
(insert-before-markers
- (format "| %s %s | %s*File time* | *%s*|\n"
+ (format (concat "| %s %s | %s%s*" (nth 8 lwords) "* | *%s*|\n")
(file-name-nondirectory (car tbl))
(if level-p "| " "") ; level column, maybe
(if timestamp "| " "") ; timestamp column, maybe
+ (if properties (make-string (length properties) ?|) "") ;properties columns, maybe
(org-minutes-to-hh:mm-string (nth 1 tbl))))) ; the time
;; Get the list of node entries and iterate over it
(if multifile "|" "") ; free space for file name column?
(if level-p (format "%d|" (car entry)) "") ; level, maybe
(if timestamp (concat (nth 2 entry) "|") "") ; timestamp, maybe
+ (if properties
+ (concat
+ (mapconcat
+ (lambda (p) (or (cdr (assoc p (nth 4 entry))) ""))
+ properties "|") "|") "") ;properties columns, maybe
(if indent (org-clocktable-indent-string level) "") ; indentation
hlc headline hlc "|" ; headline
(make-string (min (1- ntcol) (or (- level 1))) ?|)
(block (plist-get params :block))
(link (plist-get params :link))
(tags (plist-get params :tags))
+ (properties (plist-get params :properties))
+ (inherit-property-p (plist-get params :inherit-props))
+ todo-only
(matcher (if tags (cdr (org-make-tags-matcher tags))))
cc range-text st p time level hdl props tsp tbl)
(or (cdr (assoc "SCHEDULED" props))
(cdr (assoc "DEADLINE" props))
(cdr (assoc "TIMESTAMP" props))
- (cdr (assoc "TIMESTAMP_IA" props)))))
- (when (> time 0) (push (list level hdl tsp time) tbl))))))
+ (cdr (assoc "TIMESTAMP_IA" props))))
+ props (when properties
+ (remove nil
+ (mapcar
+ (lambda (p)
+ (when (org-entry-get (point) p inherit-property-p)
+ (cons p (org-entry-get (point) p inherit-property-p))))
+ properties))))
+ (when (> time 0) (push (list level hdl tsp time props) tbl))))))
(setq tbl (nreverse tbl))
(list file org-clock-file-total-minutes tbl))))
tot))))
0))))
+;; Saving and loading the clock
+
(defvar org-clock-loaded nil
"Was the clock file loaded?")
(goto-char (cdr resume-clock))
(let ((org-clock-auto-clock-resolution nil))
(org-clock-in)
- (if (org-invisible-p)
+ (if (outline-invisible-p)
(org-show-context))))))))))
;;;###autoload
(provide 'org-clock)
-
;;; org-clock.el ends here
-