Просмотр исходного кода

Implement narrowing existing agenda filters, and effort filters.

Carsten Dominik 16 лет назад
Родитель
Сommit
aead878b46
4 измененных файлов с 155 добавлено и 29 удалено
  1. 46 0
      ORGWEBPAGE/Changes.org
  2. 41 21
      doc/org.texi
  3. 4 0
      lisp/ChangeLog
  4. 64 8
      lisp/org-agenda.el

+ 46 - 0
ORGWEBPAGE/Changes.org

@@ -17,6 +17,52 @@
 :END:
 
 ** Details
+
+*** Enhancements to secondary agenda filtering
+
+**** You can now refining the current filter by an additional criterion
+      When filtering an existing agenda view with =/=, you can
+      now narrow down the existing selection by an additional
+      condition.  Do do this, use =\= instead of =/= to add the
+      aditional criterion.  You can also press =+= or =-= after
+      =/= to add a positive or negative condition.  A condition
+      can be a TAG, or an effort estimate limit, see below.
+
+**** It is now possible to filter for effort estimates
+     This means to filter the agenda for the value of the Effort
+     property.  For this you should best set up global allowed
+     values for effort estimates, with
+
+#+begin_src emacs-lisp
+(setq org-global-properties
+      '(("Effort_ALL" . "0 0:10 0:30 1:00 2:00 3:00 4:00")))
+#+end_src
+      
+     You may then select effort limits with single keys in the
+     filter.  It works like this:  After =/= or =\=, first select
+     the operater which you want to use to compare effort
+     estimates:
+
+     : <   Select entries with effort smaller than or equal to the limit
+     : >   Select entries with effort larger than or equal to the limit
+     : =   Select entries with effort equal to the limit
+
+     After that, you can press a single digit number which is
+     used as an index to the allowed effort estimates.
+
+     If you do not use digits to fast-select tags, you can even
+     skip the operator, which will then default to
+     `org-agenda-filter-effort-default-operator', which is by
+     default =<=.
+
+     Thanks to Manish for the great idea to include fast effort
+     filtering into the agenda filtering process.
+
+**** The mode line will show the active filter
+     For example, if there is a filter in place that does select
+     for HOME tags, against EMAILtags, and for tasks with an
+     estimated effort smaller than 30 minutes, the mode-line with
+     show =+HOME-EMAIL+<0:30=
    
 *** Setting tags has now its own binding, =C-c C-q=
 

+ 41 - 21
doc/org.texi

@@ -4863,10 +4863,10 @@ you want to clock your time).  For a specific buffer you can use
 @end example
 
 @noindent
-or you can set up these values globally by customizing the variables
-@code{org-global-properties} and @code{org-columns-default-format}.  In
-particular if you want to use this setup also in the agenda, a global setup
-may be advised.
+or, even better, you can set up these values globally by customizing the
+variables @code{org-global-properties} and @code{org-columns-default-format}.
+In particular if you want to use this setup also in the agenda, a global
+setup may be advised.
 
 The way to assign estimates to individual items is then to switch to column
 mode, and to use @kbd{S-@key{right}} and @kbd{S-@key{left}} to change the
@@ -4882,6 +4882,10 @@ option @code{org-agenda-columns-add-appointments-to-effort-sum}.  The
 appointments on a day that take place over a specified time interval will
 then also be added to the load estimate of the day.
 
+Effort estimates can be used in secondary agenda filtering that is triggered
+with the @kbd{/} key in the agenda (@pxref{Agenda commands}).  If you have
+these estimates defined consistently, two or three key presses will narrow
+down the list to stuff that fits into an available time slot.
 
 @node Capture, Agenda Views, Dates and Times, Top
 @chapter Capture
@@ -5835,9 +5839,7 @@ sequence in which they are found in the agenda files.
 
 Sorting can be customized using the variable
 @code{org-agenda-sorting-strategy}, and may also include criteria based on
-the estimated effort of an entry.
-@c FIXME: link!!!!!!!!
-
+the estimated effort of an entry (@pxref{Effort estimates}).
 
 @node Agenda commands, Custom agenda views, Presentation and sorting, Agenda Views
 @section Commands in the agenda buffer
@@ -6001,23 +6003,41 @@ that entry would be in the original buffer (taken from a property, from a
 
 @kindex /
 @item /
-Filter the current agenda view with respect to a tag.  You will be prompted
-for a tag selection letter.  Pressing @key{TAB} at that prompt will offer use
-completion to select a tag (including any tags that do not have a selection
-character).  The command then hides all entries that do not contain or
-inherit this tag.  When called with prefix arg, remove the entries that
-@emph{do} have the tag.  A second @kbd{/} at the prompt will unhide any
-hidden entries.  If the first key you press is either @kbd{+} or @kbd{-}, the
-previous filter will be narrowed by requiring or forbidding the selected
-additional tag.  Instead of pressing @kbd{+} or {-}, you can also use the
-following command.
+Filter the current agenda view with respect to a tag and/or effort estimates.
+The difference between this and a custom agenda commands is that filtering is
+very fast, so that you can switch quickly between different filters without
+having to recreate the agenda.
+
+You will be prompted for a tag selection letter.  Pressing @key{TAB} at that
+prompt will offer use completion to select a tag (including any tags that do
+not have a selection character).  The command then hides all entries that do
+not contain or inherit this tag.  When called with prefix arg, remove the
+entries that @emph{do} have the tag.  A second @kbd{/} at the prompt will
+turn off the filter and unhide any hidden entries.  If the first key you
+press is either @kbd{+} or @kbd{-}, the previous filter will be narrowed by
+requiring or forbidding the selected additional tag.  Instead of pressing
+@kbd{+} or {-}, you can also use the @kbd{\} command.
+
+In order to filter for effort estimates, you should set-up allowed
+efforts globally, for example
+@lisp
+(setq org-global-properties
+    '(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))
+@end lisp
+You can then filter for an effort by first typing an operator, one of @kbd{<},
+@kbd{>}, and @kbd{=}, and then the one-digit index of an effort estimate in
+your array of allowed values, where @kbd{0} means the 10th value.  The filter
+will then restrict to entries with effort smaller-or-equal, equal, or
+larger-or-equal than the selected value.  If the digits 0-9 are not used as
+fast access keys to tags, you can also simply press the index digit directly
+without an operator.  In this case, @kbd{<} will be assumed.
 
 @kindex \
 @item \
-Narrow the curent agenda fiter by an additional condition.  When called with
-prefix arg, remove the entries that @emph{do} have the tag.  You can achive
-the same effect by pressing @kbd{+} or @kbd{-} as the first key after the
-@kbd{/} command.
+Narrow the current agenda filter by an additional condition.  When called with
+prefix arg, remove the entries that @emph{do} have the tag, or that do match
+the effort criterion.  You can achieve the same effect by pressing @kbd{+} or
+@kbd{-} as the first key after the @kbd{/} command.
 
 @kindex [
 @kindex ]

+ 4 - 0
lisp/ChangeLog

@@ -1,3 +1,7 @@
+2008-10-20  Carsten Dominik  <dominik@science.uva.nl>
+
+	* org-agenda.el (org-agenda-filter-effort-default-operator): New
+	option.
 
 2008-10-18  Carsten Dominik  <dominik@science.uva.nl>
 

+ 64 - 8
lisp/org-agenda.el

@@ -387,6 +387,14 @@ or `C-c a #' to produce the list."
 	  (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string))
 	  (regexp :tag "Projects are *not* stuck if this regexp matches\ninside the subtree")))
 
+(defcustom org-agenda-filter-effort-default-operator "<"
+  "The default operator for effort estimate filtering.
+If you select an effort estimate limit with first pressing an operator,
+this one will be used."
+  :group 'org-agenda-custom-commands
+  :type '(choice (const :tag "less or equal" "<")
+		 (const :tag "greater or equal"">")
+		 (const :tag "equal" "=")))
 
 (defgroup org-agenda-skip nil
  "Options concerning skipping parts of agenda files."
@@ -4119,6 +4127,7 @@ When this is the global TODO list, a prefix argument will be interpreted."
     (goto-line line)
     (recenter window-line)))
 
+
 (defvar org-global-tags-completion-table nil)
 (defvar org-agenda-filter-tags nil)
 (defvar org-agenda-filter-form nil)
@@ -4130,20 +4139,45 @@ A lisp caller can specify CHAR.  NARROW means that the new tag should be
 used to narrow the search - the interactive user can also press `-' or `+'
 to switch to narrowing."
   (interactive "P")
-  (let ((tag-chars (mapconcat (lambda (x) (if (cdr x) (char-to-string (cdr x)) ""))
-			      org-tag-alist-for-agenda ""))
-	char a tag tags (inhibit-read-only t) (current org-agenda-filter-tags))
+  (let* ((alist org-tag-alist-for-agenda)
+	(tag-chars (mapconcat 
+		    (lambda (x) (if (cdr x) (char-to-string (cdr x)) ""))
+		    alist ""))
+	(efforts (org-split-string
+		  (or (cdr (assoc (concat org-effort-property "_ALL")
+				  org-global-properties))
+		      "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00"		      "")))
+	(effort-op org-agenda-filter-effort-default-operator)
+	(effort-prompt "")
+	(inhibit-read-only t)
+	(current org-agenda-filter-tags)
+	char a tag tags)
     (unless char
       (message 
-       "%s by tag [%s ], [TAB] to complete, [/]:restore, [+-]:narrow, [>=<]:effort: "
-       (if narrow "Filter" "Narrow") tag-chars)
+       "%s by tag [%s ], [TAB], [/]:off, [+-]:narrow, [>=<]:effort: "
+       (if narrow "Narrow" "Filter") tag-chars)
       (setq char (read-char)))
     (when (member char '(?+ ?-))
+      ;; Narrowing down
       (cond ((equal char ?-) (setq strip t narrow t))
 	    ((equal char ?+) (setq strip nil narrow t)))
       (message 
-       "Narrow by tag [%s ], [TAB] to complete, [/]:restore, [>=<]:effort: " tag-chars)
+       "Narrow by tag [%s ], [TAB], [/]:off, [>=<]:effort: " tag-chars)
       (setq char (read-char)))
+    (when (member char '(?< ?> ?=))
+      ;; An effort operator
+      (setq effort-op (char-to-string char))
+      (loop for i from 0 to 9 do
+	    (setq effort-prompt
+		  (concat
+		   effort-prompt " ["
+		   (if (= i 9) "0" (int-to-string (1+ i)))
+		   "]" (nth i efforts))))
+      (setq alist nil) ; to make sure it will be interpreted as effort.
+      (message "Effort%s: %s " effort-op effort-prompt)
+      (setq char (read-char))
+      (when (or (< char ?0) (> char ?9))
+	(error "Need 1-9,0 to select effort" )))
     (when (equal char ?\t)
       (unless (local-variable-p 'org-global-tags-completion-table (current-buffer))
 	(org-set-local 'org-global-tags-completion-table
@@ -4154,7 +4188,11 @@ to switch to narrowing."
     (cond
      ((equal char ?/) (org-agenda-filter-by-tag-show-all))
      ((or (equal char ?\ )
-	  (setq a (rassoc char org-tag-alist-for-agenda))
+	  (setq a (rassoc char alist))
+	  (and (>= char ?0) (<= char ?9)
+	       (setq n (if (= char ?0) 9 (- char ?0 1))
+		     tag (concat effort-op (nth n efforts))
+		     a (cons tag nil)))
 	  (and tag (setq a (cons tag nil))))
       (org-agenda-filter-by-tag-show-all)
       (setq tag (car a))
@@ -4185,12 +4223,30 @@ to switch to narrowing."
     (dolist (x org-agenda-filter-tags)
       (if (member x '("-" "+"))
 	  (setq f1 '(not tags))
-	(setq f1 (list 'member (substring x 1) 'tags))
+	(if (string-match "[<=>]" x)
+	    (setq f1 (org-agenda-filter-effort-form x))
+	  (setq f1 (list 'member (substring x 1) 'tags)))
 	(if (equal (string-to-char x) ?-)
 	    (setq f1 (list 'not f1))))
       (push f1 f))
     (cons 'and (nreverse f))))
 
+(defun org-agenda-filter-effort-form (e)
+  "Return the form to compare the effort of the current line with what E says.
+E looks line \"+<2:25\"."
+  (let (op)
+    (setq e (substring e 1))
+    (setq op (string-to-char e) e (substring e 1))
+    (setq op (if (equal op ?<) '<= (if (equal op ?>) '>= '=)))
+    (list 'org-agenda-compare-effort (list 'quote op)
+	  (org-hh:mm-string-to-minutes e))))
+
+(defun org-agenda-compare-effort (op value)
+  (let ((eff (get-text-property 'effort-minutes)))
+    (if (not eff)
+	nil ; we don't have an effort defined
+      (funcall op eff value))))
+
 (defvar org-agenda-filter-overlays nil)
 
 (defun org-agenda-filter-by-tag-hide-line ()