On Tue, May 26, 2009 at 4:45 PM, Carsten Dominik <carsten.domi...@gmail.com> wrote: > > On May 26, 2009, at 4:26 PM, Konstantin Antipin wrote: > >> Carsten, thank you for explanation. >> Hopefully, I will get FSF papers soon. >> >> In a meanwhile, here is another patch that introduces following changes: >> >> In case we set effort estimate on the currently clocked item, >> show message when time is up (notification is shown only once) >> * Linux only: If libnotify is used - the standard notification >> system in linux, then show notification with it. >> Note: Additional package libnotify-bin should be installed. >> Additionally, if variable org-clock-sound is set, interpret it as >> path to sound file >> and play it (wav files only). >> * If aplay (tool from alsa - standard linux sound system) is >> available play sound >> with it (all type of files). >> >> So, if someone has interest in this features, please try it. >> I also would like to discuss If we want this functionality (sound and >> notification) in the core, >> or it is better to put it to the extension... Or, just introduce >> another variable that controls if we show notification or not... > > I think we can put this into the core if: > > - this will work without crashing on any system where Emacs runs on, > i.e. if the re is no way to play a sound file, fall back to (ding) > with a message or so... Well, I made it such, that * If you are using linux * and if you have libnotify or aplay in your $PATH, then libnotify or aplay will be used. If not, use simple message and emacs-beep. It should not break things... > > >> >> >> TODO: >> * As proposed by Daniel, give user an option to see total time, spend >> on the task instead of currently clocked time. >> In fact, this functionality requires refactoring of org-clock-sum >> function. Is it ok, if I do it? > > Maybe you don't really need to refactor it: > > (save-restriction > (org-narrow-to-subtree) > (org-clock-sum) > org-clock-file-total-minutes) > > will give you the total clocked time in minutes.
Coool! so elegantly simple! I used it in the current patch. DONE: Show total clocked time in mode line. (Instead of time since last start) In fact, now I simply changed the default behavior - now mode-line shows total clocked time, without giving user a preference. I thought it is more logical behavior... Or should I introduce defcustom that controls it? Probably I am sending too much patches around :) Just a suggestion: why don't we use github for org-mode hosting? It would be soooo simple to contribute and to manage things! You would only benefit from this, Carsten.;) Github is a really nice service. And free, of course. Transition to it would be a breeze as well. I can help, if needed with this... Konstantin > > - Carsten > >> >> best, >> Konstantin >> >> patch is made on the git version of orgmode. >> >> >> >> >> On Tue, May 26, 2009 at 3:18 PM, Carsten Dominik >> <carsten.domi...@gmail.com> wrote: >>> >>> On May 25, 2009, at 5:43 PM, Konstantin Antipin wrote: >>> >>>> Here is the patch to org-clock.el that does show estimated effort in >>>> the mode-line if it is set. Like so: 01:20/01:30 (clocked >>>> time/estimated time) >>>> It does it by: >>>> * Setting new variable org-clock-effort in org-clock-in function. >>>> * If org-clock-effort is not nil, show estimated effort in the >>>> mode-line. >>>> >>>> I would like to go further and do the following: >>>> * Make a beep/or highlight if we spend more time on a task that >>>> initially intended >>>> * As proposed by Daniel, give user an option to see total time, spend >>>> on the task instead of currently clocked time. >>>> >>>> Does somebody else need this? Will this changes be accepted to the >>>> orgmode-core? >>>> I just saw that in order to contribute, you need to sign some papers.. >>>> Is this the only way? >>>> I am new to open-source, so I am not really familiar with such things. >>> >>> >>> Hi Konstantin, >>> >>> this is interesting functionality which I would like to have in the core. >>> >>> I can accept short patches of only a few lines without the paperwork, but >>> your patch is already at the limit, and adding the other ideas you have >>> will push it over that limit. We have the following possibilities: >>> >>> 1. You sign the papers. This is very simple to do, unless you have >>> an employer who owns everything you do and who might make problems. >>> This would be my preferred solution. >>> >>> 2. I can put stuff without FSF copyright assignment into the >>> contrib directory - you could make a little package that hooks >>> into Org, I would created any hooks needed. >>> >>> 3. I treat your contribution as an "idea/feature request" and implement >>> it myself. As I have many other things to do, this is my least >>> preferred >>> solution. >>> >>> If you decide to sign the papers, please get the form from the homepage >>> orgmode.org (near te end) and send it to the FSF, with a CC to me. This >>> will take you no more than 2 minutes. We can then proceed with >>> integrating >>> your stuff into the Org core, but I will be able to integrate this change >>> into Emacs only after I receive confirmation about the signed paper, >>> which >>> will happen within a fee weeks or so. >>> >>> - Carsten >>> >>>> >>>> best, >>>> Konstantin >>>> >>>> >>>> On Mon, May 25, 2009 at 12:44 PM, Eraldo Helal <ad...@eraldo.at> wrote: >>>>> >>>>> Sounds good to me. >>>>> >>>>> Eraldo >>>>> >>>>> On Mon, May 25, 2009 at 12:30, Konstantin Antipin >>>>> <antipin.konstan...@googlemail.com> wrote: >>>>>> >>>>>> Hi Daniel, >>>>>> Yes, you are right indeed. I am talking about effort estimates - I'v >>>>>> missed this chapter for some reason from the manual. >>>>>> I like the idea you proposed - to show how much time is left in the >>>>>> mode line. And I think I am going to write necessary code for this. >>>>>> >>>>>> Or, may be someone has even better idea? >>>>>> >>>>>> best, >>>>>> Konstantin >>>>>> >>>>>> On Mon, May 25, 2009 at 11:25 AM, Daniel Clemente <n142...@gmail.com> >>>>>> wrote: >>>>>>> >>>>>>> Hi. >>>>>>> I suppose you talk about estimated efforts. I also have noticed that >>>>>>> I >>>>>>> work better if I have defined them, but it is very easy to miss them >>>>>>> and >>>>>>> work on a task more time than planned. >>>>>>> An easy improvement would be to show at the mode line not only how >>>>>>> much time you have worked on the current task but also the remaining >>>>>>> time >>>>>>> according to your effort estimate. And if it comes to 0, highlight it >>>>>>> noticeably. >>>>>>> >>>>>>> Other useful things to show would be the *total* elapsed time (not >>>>>>> only the elapsed time of the last C-c C-x C-i) or directly the effort >>>>>>> estimate (instead of the remaining time, the total time). >>>>>>> >>>>>>> And as you say, an alarm would be useful. >>>>>>> >>>>>>> -- Daniel >>>>>>> >>>>>>> El dl, mai 25 2009, Konstantin Antipin va escriure: >>>>>>>> >>>>>>>> Hi everybody! >>>>>>>> I am constantly trying to be more productive, and there is one thing >>>>>>>> that I noticed: >>>>>>>> If you give yourself a specific time for a task, then you tend to >>>>>>>> finish this task in this time. It helps to stay focused and do stuff >>>>>>>> that is most important. >>>>>>>> >>>>>>>> So, the question is - Is there any way to set a timer on a taks, and >>>>>>>> get a bell when it is expired? >>>>>>>> Some time before I even wrote a small extension that helps me to do >>>>>>>> that http://www.emacswiki.org/emacs/tea-time >>>>>>>> But now I am thinking - is there an orgmode-way to do that? It would >>>>>>>> be great to integrate it with great time tracking system, for >>>>>>>> example... >>>>>>>> If nobody uses proposed feature, please give me a hint how it would >>>>>>>> be >>>>>>>> best to do that. >>>>>>>> >>>>>>>> >>>>>>>> my best, >>>>>>>> Konstantin >>>>>>>> >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> Emacs-orgmode mailing list >>>>>>>> Remember: use `Reply All' to send replies to the list. >>>>>>>> Emacs-orgmode@gnu.org >>>>>>>> http://lists.gnu.org/mailman/listinfo/emacs-orgmode >>>>>>> >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> Emacs-orgmode mailing list >>>>>> Remember: use `Reply All' to send replies to the list. >>>>>> Emacs-orgmode@gnu.org >>>>>> http://lists.gnu.org/mailman/listinfo/emacs-orgmode >>>>>> >>>>> >>>> <clock-efforts.patch>_______________________________________________ >>>> Emacs-orgmode mailing list >>>> Remember: use `Reply All' to send replies to the list. >>>> Emacs-orgmode@gnu.org >>>> http://lists.gnu.org/mailman/listinfo/emacs-orgmode >>> >>> >> <clock-effort-notify.patch> > >
diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 87ca180..e844467 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -148,6 +148,15 @@ All this depends on running `org-clock-persistence-insinuate' in .emacs" :group 'org-clock :type 'boolean) + +(defcustom org-clock-sound nil + "Sound that will play once timer is expired. +If you don't have alsa, it is better to be .wav file" + :group 'org-clock + :type 'string + ) + + ;;; The clock for measuring work time. (defvar org-mode-line-string "") @@ -158,6 +167,12 @@ All this depends on running `org-clock-persistence-insinuate' in .emacs" (defvar org-clock-heading-for-remember "") (defvar org-clock-start-time "") +(defvar org-clock-effort "" + "Effort estimate of the currently clocking task") + +(defvar org-clock-total-time "" + "Holds total time, spent on currently clocked item before start of current clock.") + (defvar org-clock-history nil "List of marker pointing to recent clocked tasks.") @@ -254,9 +269,9 @@ pointing to it." (org-get-category))) heading (org-get-heading 'notags) prefix (save-excursion - (org-back-to-heading t) - (looking-at "\\*+ ") - (match-string 0)) + (org-back-to-heading t) + (looking-at "\\*+ ") + (match-string 0)) task (substring (org-fontify-like-in-org-mode (concat prefix heading) @@ -266,24 +281,106 @@ pointing to it." (insert (format "[%c] %-15s %s\n" i cat task)) (cons i marker))))) + +(defun org-clock-sum-current-item () + "Returns time, clocked on current item in total" + (save-restriction + (org-narrow-to-subtree) + (org-clock-sum) + org-clock-file-total-minutes) + ) + +(defun org-clock-get-clock-string () + "Form a clock-string, that will be show in the mode line. +If effort estimate was defined for current item, then use 01:30/01:50 format (clocked/estimated). +If not, then 01:50 format (clocked). +" + (let* ((clocked-time (org-clock-get-clocked-time)) + (h (floor clocked-time 60)) + (m (- clocked-time (* 60 h))) + ) + (if (and org-clock-effort) + (let* ((effort-in-minutes (org-hh:mm-string-to-minutes org-clock-effort)) + (effort-h (floor effort-in-minutes 60)) + (effort-m (- effort-in-minutes (* effort-h 60))) + ) + (format (concat "-[" org-time-clocksum-format "/" org-time-clocksum-format " (%s)]") + h m effort-h effort-m org-clock-heading) + ) + (format (concat "-[" org-time-clocksum-format " (%s)]") + h m org-clock-heading)) + )) + (defun org-clock-update-mode-line () - (let* ((delta (- (time-to-seconds (current-time)) - (time-to-seconds org-clock-start-time))) - (h (floor delta 3600)) - (m (floor (- delta (* 3600 h)) 60))) - (setq org-mode-line-string - (org-propertize - (let ((clock-string (format (concat "-[" org-time-clocksum-format " (%s)]") - h m org-clock-heading)) - (help-text "Org-mode clock is running. Mouse-2 to go there.")) - (if (and (> org-clock-string-limit 0) - (> (length clock-string) org-clock-string-limit)) - (org-propertize (substring clock-string 0 org-clock-string-limit) - 'help-echo (concat help-text ": " org-clock-heading)) - (org-propertize clock-string 'help-echo help-text))) - 'local-map org-clock-mode-line-map - 'mouse-face (if (featurep 'xemacs) 'highlight 'mode-line-highlight))) - (force-mode-line-update))) + (setq org-mode-line-string + (org-propertize + (let ((clock-string (org-clock-get-clock-string)) + (help-text "Org-mode clock is running. Mouse-2 to go there.")) + (if (and (> org-clock-string-limit 0) + (> (length clock-string) org-clock-string-limit)) + (org-propertize (substring clock-string 0 org-clock-string-limit) + 'help-echo (concat help-text ": " org-clock-heading)) + (org-propertize clock-string 'help-echo help-text))) + 'local-map org-clock-mode-line-map + 'mouse-face (if (featurep 'xemacs) 'highlight 'mode-line-highlight))) + (if org-clock-effort (org-clock-notify-once-if-expired)) + (force-mode-line-update)) + + +(defun org-clock-get-clocked-time () + "In minutes." + (let ((currently-clocked-time (floor (- (time-to-seconds (current-time)) + (time-to-seconds org-clock-start-time)) 60))) + ;; (if org-clock-effort + (+ currently-clocked-time org-clock-total-time) + ;; currently-clocked-time + ;; ) + )) + +(defvar org-clock-notification-was-shown nil + "Shows if we have shown notification already.") + +(defun org-clock-notify-once-if-expired () + "Show notification if we spent more time then we estimated before. +Notification is shown only once." + (let ((effort-in-minutes (org-hh:mm-string-to-minutes org-clock-effort)) + (clocked-time (org-clock-get-clocked-time))) + (if (>= clocked-time effort-in-minutes) + (if (not org-clock-notification-was-shown) + (progn (org-clock-play-sound) + (show-notification (format "Task '%s' should be finished by now. (%s)" + org-clock-heading org-clock-effort)) + (setq org-clock-notification-was-shown t))) + (setq org-clock-notification-was-shown nil) + ) + )) + +(setq org-clock-sound "/usr/share/sounds/purple/login.wav") + +(defun show-notification (notification) + "Show notification. Use libnotify, if available." + (if (program-exists "notify-send") + (start-process "emacs-timer-notification" nil "notify-send" notification) + (message notification) + )) + + +(defun org-clock-play-sound () + "Play sound. +Use alsa's aplay tool if available." + (if (not (eq nil org-clock-sound)) + (if (program-exists "aplay") + (start-process "org-clock-play-notification" nil "aplay" org-clock-sound) + (play-sound-file org-clock-sound)) + (progn (beep t) (beep t))) + ) + +(defun program-exists (program-name) + "Checks whenever we can locate program and launch it." + (if (eq system-type 'gnu/linux) + (= 0 (call-process "which" nil nil nil program-name)) + )) + (defvar org-clock-mode-line-entry nil "Information for the modeline about the running clock.") @@ -387,6 +484,8 @@ the clocking selection, associated with the letter `d'." (beginning-of-line 1) (org-indent-line-to (- (org-get-indentation) 2))) (insert org-clock-string " ") + (setq org-clock-effort (org-get-effort)) + (setq org-clock-total-time (org-clock-sum-current-item)) (setq org-clock-start-time (current-time)) (setq ts (org-insert-time-stamp org-clock-start-time 'with-hm 'inactive)))) (move-marker org-clock-marker (point) (buffer-base-buffer)) @@ -473,11 +572,11 @@ line and position cursor in that line." (and (integerp org-clock-into-drawer) (< org-clock-into-drawer 2))) (insert ":" drawer ":\n:END:\n") - (beginning-of-line -1) - (org-indent-line-function) + (beginning-of-line -1) + (org-indent-line-function) (org-flag-drawer t) - (beginning-of-line 2) - (org-indent-line-function) + (beginning-of-line 2) + (org-indent-line-function) (beginning-of-line) (or org-log-states-order-reversed (and (re-search-forward org-property-end-re nil t) @@ -488,48 +587,48 @@ line and position cursor in that line." If there is no running clock, throw an error, unless FAIL-QUIETLY is set." (interactive) (catch 'exit - (if (not (marker-buffer org-clock-marker)) - (if fail-quietly (throw 'exit t) (error "No active clock"))) - (let (ts te s h m remove) - (save-excursion - (set-buffer (marker-buffer org-clock-marker)) - (save-restriction - (widen) - (goto-char org-clock-marker) - (beginning-of-line 1) - (if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp)) - (equal (match-string 1) org-clock-string)) - (setq ts (match-string 2)) - (if fail-quietly (throw 'exit nil) (error "Clock start time is gone"))) - (goto-char (match-end 0)) - (delete-region (point) (point-at-eol)) - (insert "--") - (setq te (org-insert-time-stamp (current-time) 'with-hm 'inactive)) - (setq s (- (time-to-seconds (apply 'encode-time (org-parse-time-string te))) - (time-to-seconds (apply 'encode-time (org-parse-time-string ts)))) - h (floor (/ s 3600)) - s (- s (* 3600 h)) - m (floor (/ s 60)) - s (- s (* 60 s))) - (insert " => " (format "%2d:%02d" h m)) - (when (setq remove (and org-clock-out-remove-zero-time-clocks - (= (+ h m) 0))) + (if (not (marker-buffer org-clock-marker)) + (if fail-quietly (throw 'exit t) (error "No active clock"))) + (let (ts te s h m remove) + (save-excursion + (set-buffer (marker-buffer org-clock-marker)) + (save-restriction + (widen) + (goto-char org-clock-marker) (beginning-of-line 1) + (if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp)) + (equal (match-string 1) org-clock-string)) + (setq ts (match-string 2)) + (if fail-quietly (throw 'exit nil) (error "Clock start time is gone"))) + (goto-char (match-end 0)) (delete-region (point) (point-at-eol)) - (and (looking-at "\n") (> (point-max) (1+ (point))) - (delete-char 1))) - (move-marker org-clock-marker nil) - (when org-log-note-clock-out - (org-add-log-setup 'clock-out nil nil nil nil - (concat "# Task: " (org-get-heading t) "\n\n"))) - (when org-clock-mode-line-timer - (cancel-timer org-clock-mode-line-timer) - (setq org-clock-mode-line-timer nil)) - (setq global-mode-string - (delq 'org-mode-line-string global-mode-string)) - (force-mode-line-update) - (message (concat "Clock stopped at %s after HH:MM = " org-time-clocksum-format "%s") te h m - (if remove " => LINE REMOVED" ""))))))) + (insert "--") + (setq te (org-insert-time-stamp (current-time) 'with-hm 'inactive)) + (setq s (- (time-to-seconds (apply 'encode-time (org-parse-time-string te))) + (time-to-seconds (apply 'encode-time (org-parse-time-string ts)))) + h (floor (/ s 3600)) + s (- s (* 3600 h)) + m (floor (/ s 60)) + s (- s (* 60 s))) + (insert " => " (format "%2d:%02d" h m)) + (when (setq remove (and org-clock-out-remove-zero-time-clocks + (= (+ h m) 0))) + (beginning-of-line 1) + (delete-region (point) (point-at-eol)) + (and (looking-at "\n") (> (point-max) (1+ (point))) + (delete-char 1))) + (move-marker org-clock-marker nil) + (when org-log-note-clock-out + (org-add-log-setup 'clock-out nil nil nil nil + (concat "# Task: " (org-get-heading t) "\n\n"))) + (when org-clock-mode-line-timer + (cancel-timer org-clock-mode-line-timer) + (setq org-clock-mode-line-timer nil)) + (setq global-mode-string + (delq 'org-mode-line-string global-mode-string)) + (force-mode-line-update) + (message (concat "Clock stopped at %s after HH:MM = " org-time-clocksum-format "%s") te h m + (if remove " => LINE REMOVED" ""))))))) (defun org-clock-cancel () "Cancel the running clock be removing the start timestamp." @@ -574,7 +673,7 @@ With prefix arg SELECT, offer recently clocked tasks for selection." (defvar org-clock-file-total-minutes nil "Holds the file total time in minutes, after a call to `org-clock-sum'.") - (make-variable-buffer-local 'org-clock-file-total-minutes) +(make-variable-buffer-local 'org-clock-file-total-minutes) (defun org-clock-sum (&optional tstart tend) "Sum the times for each subtree. @@ -870,7 +969,7 @@ the currently selected interval size." ((string-match "\\([0-9]+\\)\\(-\\([wW]?\\)\\([0-9]\\{1,2\\}\\)\\(-\\([0-9]\\{1,2\\}\\)\\)?\\)?" s) ;; 1 1 2 3 3 4 4 5 6 6 5 2 (setq y (string-to-number (match-string 1 s)) - wp (and (match-end 3) (match-string 3 s)) + wp (and (match-end 3) (match-string 3 s)) mw (and (match-end 4) (string-to-number (match-string 4 s))) d (and (match-end 6) (string-to-number (match-string 6 s)))) (cond
_______________________________________________ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode