1 ;;; planner-tasks-overview.el --- Task summary for planner.el
3 ;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
5 ;; Emacs Lisp Archive Entry
6 ;; Filename: planner-tasks-overview.el
7 ;; Keywords: hypermedia
8 ;; Author: Sandra Jean Chua (Sacha) <sacha@free.net.ph>
9 ;; Description: Task overview for planner.el files
10 ;; URL: http://www.plannerlove.com/
11 ;; Compatibility: Emacs20, Emacs21
13 ;; This file is part of Planner. It is not part of GNU Emacs.
15 ;; Planner is free software; you can redistribute it and/or modify it
16 ;; under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2, or (at your option)
20 ;; Planner is distributed in the hope that it will be useful, but
21 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 ;; General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with Planner; see the file COPYING. If not, write to the
27 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 ;; Boston, MA 02110-1301, USA.
32 ;; You can use `planner-tasks-overview' to see a list of tasks between
33 ;; two dates. `planner-tasks-overview-jump' jumps to the linked task.
34 ;; To change the sort order, invoke the following functions:
35 ;; `planner-tasks-overview-sort-by-date'
36 ;; `planner-tasks-overview-sort-by-plan'
37 ;; `planner-tasks-overview-sort-by-category'
38 ;; `planner-tasks-overview-sort-by-status'
40 ;; This file was inspired by Markus Hoenicka's
41 ;; http://www.mhoenicka.de/software/hacks/tasklist.html and Frederick
42 ;; Fouvry's Lisp port of tasklist.pl.
46 ;; Andrew J. Korty (ajk AT iu DOT edu) provided a patch that corrected
47 ;; a typo in the keymap.
49 ;; Yann Hodique helped port this to Muse.
55 (defvar planner-tasks-overview-mode-map
56 (let ((map (make-sparse-keymap)))
57 (define-key map
"1" 'planner-tasks-overview-sort-by-date
)
58 (define-key map
"2" 'planner-tasks-overview-sort-by-plan
)
59 (define-key map
"3" 'planner-tasks-overview-sort-by-priority
)
60 (define-key map
"4" 'planner-tasks-overview-sort-by-status
)
61 (define-key map
"j" 'planner-tasks-overview-jump
)
62 (define-key map
"o" 'planner-tasks-overview
)
64 (define-key map
[tab] 'planner-next-reference)
65 (define-key map [(control ?i)] 'planner-next-reference)
66 (if (featurep 'xemacs)
67 (define-key map [(shift tab)] 'planner-previous-reference)
68 (define-key map [(shift iso-lefttab)] 'planner-previous-reference)
69 (define-key map [(shift control ?i)] 'planner-previous-reference))
71 "Keymap for planner task overview buffers.")
73 (define-derived-mode planner-tasks-overview-mode fundamental-mode "Overview"
74 "Planner tasks overview.
75 \\{planner-tasks-overview-mode-map}")
77 (defvar planner-tasks-overview-data nil "Task data.")
78 (make-variable-buffer-local 'planner-tasks-overview-data)
79 (defvar planner-tasks-overview-buffer "*planner tasks overview*"
83 (defun planner-tasks-overview (start end)
84 "Display a task overview from START to END."
85 (interactive (list (planner-read-date)
87 (when (get-buffer planner-tasks-overview-buffer)
88 (kill-buffer planner-tasks-overview-buffer))
89 (with-current-buffer (get-buffer-create planner-tasks-overview-buffer)
90 (planner-tasks-overview-mode)
91 (setq planner-tasks-overview-data
92 (planner-tasks-overview-extract-all-tasks
93 (planner-get-day-pages start end)))
94 (setq truncate-lines t)
95 (set (make-local-variable 'truncate-partial-width-windows) t)
96 (planner-tasks-overview-sort-by-date)
97 (switch-to-buffer (current-buffer))))
100 (defun planner-tasks-overview-jump-other-window ()
101 "Display the task under point in a different window."
103 (planner-tasks-overview-jump t))
106 (defun planner-tasks-overview-jump (&optional other-window)
107 "Display the task under point."
110 (switch-to-buffer-other-window (current-buffer)))
111 (let* ((info (get-text-property (point) 'info))
112 (page (or (elt info 2) (elt info 3))))
113 (planner-find-file page)
114 (goto-char (point-min))
116 (when (re-search-forward
118 "#[A-C][0-9]*\\s-+.\\s-+"
119 (regexp-quote (elt info 4))) nil t)
120 (goto-char (planner-line-beginning-position)))))
122 (defun planner-tasks-overview-sort-by-field (field)
125 (setq planner-tasks-overview-data
126 (sort planner-tasks-overview-data
127 (lambda (a b) (string< (elt a field) (elt b field)))))
128 (planner-tasks-overview-insert))
130 (defun planner-tasks-overview-sort-by-date ()
133 (planner-tasks-overview-sort-by-field 2))
135 (defun planner-tasks-overview-sort-by-plan ()
138 (planner-tasks-overview-sort-by-field 3))
140 (defun planner-tasks-overview-sort-by-priority ()
143 (planner-tasks-overview-sort-by-field 0))
145 (defun planner-tasks-overview-sort-by-status ()
148 (setq planner-tasks-overview-data
149 (sort planner-tasks-overview-data
151 (if (string= (elt b 1)
157 '("_" "o" "D" "P" "X" "C")))))))
158 (planner-tasks-overview-insert))
160 (defun planner-tasks-overview-insert ()
161 "Insert the textual representation for `planner-tasks-overview-data'.
162 DATA is a list of (priority status date plan description)."
163 (with-current-buffer (get-buffer-create "*planner tasks overview*")
164 (setq buffer-read-only nil)
166 (let (last-date last-plan)
170 (format "%10s | %s | %s %s | %s\n"
175 (if (string= last-date (elt item 2))
178 (format "%-10.10s" "nil"))
183 (if (string= last-plan (elt item 3))
184 "____________________"
186 (format "%-20.20s" "nil"))
190 (add-text-properties 0 (length text) (list 'info item)
193 (setq last-date (elt item 2))
194 (setq last-plan (elt item 3)))
195 planner-tasks-overview-data)
197 (goto-char (point-min))
198 (setq buffer-read-only t))))
200 (defun planner-tasks-overview-extract-all-tasks (file-list)
201 "Return a list of all tasks on pages in FILE-LIST."
204 (cd (planner-directory))
205 ;; The following line greps only the days limited by START and END.
206 (apply 'call-process "grep" nil t nil "-H" "-e" "^#[A-C][0-9]*"
207 (mapcar 'cdr file-list))
208 (goto-char (point-min))
210 (when (looking-at "^\\([^:\n]+\\):\\(.+\\)")
211 (let ((info (planner-task-info-from-string
212 (match-string 1) (match-string 2))))
215 (vector (planner-task-priority info)
216 (planner-task-status info)
217 (planner-task-date info)
218 (planner-task-plan info)
219 (planner-task-description info)))))
223 ;; Improvements: sort?
225 (defun planner-tasks-overview-show-summary (&optional file-list)
226 "Count unscheduled, scheduled, and completed tasks for FILE-LIST.
227 If called with an interactive prefix, prompt for the page(s) to
228 display. planner-multi is required for multiple pages."
231 (if current-prefix-arg
234 (if (featurep 'planner-multi)
235 (mapcar 'planner-link-base
237 (planner-read-non-date-page
238 (planner-file-alist))))
239 (list (planner-read-non-date-page
240 (planner-file-alist))))))))
243 (setq data (planner-tasks-overview-get-summary file-list))
244 (with-current-buffer (get-buffer-create "*planner tasks overview*")
245 (setq buffer-read-only nil)
247 (setq total (+ (elt data 0) (elt data 1) (elt data 2)))
248 (insert (format "Total unfinished, unscheduled tasks : %3d (%6.2f%%)\n"
249 (elt data 0) (/ (elt data 0) (* 0.01 total)))
250 (format "Total unfinished, scheduled tasks : %3d (%6.2f%%)\n"
251 (elt data 1) (/ (elt data 1) (* 0.01 total)))
252 (format "Total finished tasks : %3d (%6.2f%%)\n\n"
253 (elt data 2) (/ (elt data 2) (* 0.01 total))))
254 (insert (format "%-40s | Unsched | Sched | Complete | Total\n"
258 (let ((row-total (* 0.01 (+ (elt row 1) (elt row 2) (elt row 3)))))
260 (format "%s | %3d %3.0f%% | %3d %3.0f%% | %3d %3.0f%% | %3d %3.0f%%\n"
263 (format "%-40.40s" (elt row 0)))
265 (/ (elt row 1) row-total)
267 (/ (elt row 2) row-total)
269 (/ (elt row 3) row-total)
270 (+ (elt row 1) (elt row 2) (elt row 3))
271 (/ (+ (elt row 1) (elt row 2) (elt row 3))
274 (cd (planner-directory))
276 (switch-to-buffer (current-buffer))))))
278 ;; Unfinished Finished % Complete
279 ;; Unscheduled Scheduled
280 (defun planner-tasks-overview-get-summary (&optional file-list)
281 "Return a summary of tasks on pages in FILE-LIST.
282 List is of the form (total-unfinished-unscheduled
283 total-unfinished-scheduled total-finished data), where data is a
284 list of the form (plan unfinished-unscheduled
285 unfinished-scheduled finished)."
286 (let ((total-unfinished-unscheduled 0)
287 (total-unfinished-scheduled 0)
290 (unless file-list (setq file-list (planner-file-alist)))
294 (unless (string-match planner-date-regexp (car (car file-list)))
295 (let ((unfinished-unscheduled 0)
296 (unfinished-scheduled 0)
299 (insert-file-contents (cdr (car file-list)))
300 (goto-char (point-min))
301 (while (re-search-forward planner-task-regexp nil t)
302 (let ((info (planner-task-info-from-string
303 (car (car file-list))
305 (planner-line-beginning-position)
306 (planner-line-end-position)))))
308 ((or (string= (planner-task-status info) "X")
309 (string= (planner-task-status info) "C"))
310 (setq finished (1+ finished)))
311 ((planner-task-date info)
312 (setq unfinished-scheduled (1+ unfinished-scheduled)))
313 (t (setq unfinished-unscheduled
314 (1+ unfinished-unscheduled))))))
315 (setq list (cons (list (car (car file-list))
316 unfinished-unscheduled
320 (setq total-unfinished-unscheduled
321 (+ total-unfinished-unscheduled unfinished-unscheduled))
322 (setq total-unfinished-scheduled
323 (+ total-unfinished-scheduled unfinished-scheduled))
325 (+ total-finished finished))))
326 (setq file-list (cdr file-list)))))
327 (list total-unfinished-unscheduled
328 total-unfinished-scheduled
332 (provide 'planner-tasks-overview)
334 ;;; planner-tasks-overview.el ends here