]> code.delx.au - gnu-emacs/blobdiff - lisp/org/org-clock.el
Merge from emacs-24
[gnu-emacs] / lisp / org / org-clock.el
index 4e30dd90d80607c0d5c8850af7901e9365d40846..c39fb249e74cb8fd09154b0175cd8511659fe0f7 100644 (file)
@@ -1,11 +1,10 @@
 ;;; 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.
 ;;
@@ -28,6 +27,7 @@
 ;; This file contains the time clocking code for Org-mode
 
 (require 'org)
+(require 'org-exp)
 ;;; Code:
 
 (eval-when-compile
@@ -35,7 +35,9 @@
 
 (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."
@@ -62,6 +64,22 @@ which see."
          (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.
@@ -125,7 +143,7 @@ The function is called with point at the beginning of the headline."
   :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)
 
@@ -184,7 +202,7 @@ file name  play this sound file.  If not possible, fall back to beep"
          (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:
 
@@ -201,13 +219,15 @@ auto     Automatically, either `all', or `repeat' for repeating tasks"
          (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")))
@@ -227,35 +247,49 @@ string as argument."
   :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
@@ -281,11 +315,13 @@ play with them."
 (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
@@ -387,6 +423,9 @@ of a different task.")
   "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)
@@ -419,6 +458,7 @@ of a different task.")
           (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))
@@ -441,13 +481,11 @@ pointing to it."
            (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
@@ -458,7 +496,7 @@ pointing to it."
        (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.")
@@ -473,13 +511,13 @@ If not, show simply the clocked time like 01:50."
         (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
@@ -495,7 +533,7 @@ If not, show simply the clocked time like 01:50."
 (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))
@@ -509,10 +547,10 @@ If not, show simply the clocked time like 01:50."
         '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))
 
@@ -547,10 +585,10 @@ the mode line."
        ;; 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)))))
@@ -567,9 +605,9 @@ the mode line."
   "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)))
@@ -626,12 +664,12 @@ Use alsa's aplay tool if available."
              (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."
@@ -660,7 +698,7 @@ Use alsa's aplay tool if available."
         (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)
@@ -676,7 +714,7 @@ This macro also protects the current active clock from being altered."
                                  (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)
@@ -746,7 +784,8 @@ If necessary, clock-out of the currently active clock."
 
 (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"))
@@ -961,6 +1000,16 @@ so long."
                         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.
@@ -978,6 +1027,7 @@ the clocking selection, associated with the letter `d'."
          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))
@@ -986,11 +1036,17 @@ the clocking selection, associated with the letter `d'."
        (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.
@@ -1005,7 +1061,8 @@ the clocking selection, associated with the letter `d'."
                     (= (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
@@ -1014,13 +1071,9 @@ the clocking selection, associated with the letter `d'."
        (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)
@@ -1045,7 +1098,7 @@ the clocking selection, associated with the letter `d'."
                                            (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)))
@@ -1069,9 +1122,9 @@ the clocking selection, associated with the letter `d'."
            (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))
@@ -1138,16 +1191,6 @@ the clocking selection, associated with the letter `d'."
            (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)
@@ -1197,22 +1240,23 @@ When FIND-UNCLOSED is non-nil, first check if there is an unclosed clock
 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))
@@ -1239,7 +1283,10 @@ line and position cursor in that line."
        (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)
@@ -1339,7 +1386,7 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
                                           (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))))))
@@ -1349,6 +1396,76 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
           (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)
@@ -1387,7 +1504,7 @@ With prefix arg SELECT, offer recently clocked tasks for selection."
              (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)
@@ -1502,7 +1619,9 @@ nil are excluded from the clock summation."
 (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)
@@ -1579,16 +1698,18 @@ from the `before-change-functions' in the current buffer."
       (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))
@@ -1628,7 +1749,10 @@ fontified, and then returned."
 (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")
@@ -1638,21 +1762,14 @@ buffer and update it."
     (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
@@ -1800,7 +1917,7 @@ the returned times will be formatted strings."
                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))))
@@ -1879,7 +1996,8 @@ the currently selected interval size."
                         (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)))))
@@ -1895,7 +2013,8 @@ the currently selected interval size."
                (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)))))
@@ -1931,7 +2050,6 @@ the currently selected interval size."
                          '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
@@ -1986,7 +2104,7 @@ the currently selected interval size."
            (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)))
@@ -2006,13 +2124,17 @@ the currently selected interval size."
   "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))
@@ -2024,6 +2146,7 @@ from the dynamic block defintion."
         (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))
@@ -2072,7 +2195,7 @@ from the dynamic block defintion."
        (or header
           ;; Format the standard header
           (concat
-           "Clock summary at ["
+           (nth 9 lwords) " ["
            (substring
             (format-time-string (cdr org-time-stamp-formats))
             1 -1)
@@ -2087,24 +2210,29 @@ from the dynamic block defintion."
         (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
@@ -2121,12 +2249,13 @@ from the dynamic block defintion."
            (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
@@ -2151,6 +2280,11 @@ from the dynamic block defintion."
               (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))) ?|)
@@ -2305,6 +2439,9 @@ TIME:      The sum of all time spend in this tree, in minutes.  This time
         (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)
 
@@ -2358,8 +2495,15 @@ TIME:      The sum of all time spend in this tree, in minutes.  This time
                          (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))))
 
@@ -2387,6 +2531,8 @@ This function is made for clock tables."
                        tot))))
        0))))
 
+;; Saving and loading the clock
+
 (defvar org-clock-loaded nil
   "Was the clock file loaded?")
 
@@ -2478,7 +2624,7 @@ The details of what will be saved are regulated by the variable
              (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
@@ -2492,6 +2638,4 @@ The details of what will be saved are regulated by the variable
 
 (provide 'org-clock)
 
-
 ;;; org-clock.el ends here
-