Fix problem introduced by recent commit that broke using SPC as separator.
[planner-el.git] / planner-tasks-overview.el
blob91a0a6e86aaa096d0aa6675a8f4e9053177ea9ee
1 ;;; planner-tasks-overview.el --- Task summary for planner.el
2 ;;
3 ;; Copyright (C) 2004, 2005, 2007, 2008 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.wjsullivan.net/PlannerMode.html
11 ;; Compatibility: Emacs20, Emacs21, Emacs22, XEmacs21
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 3, or (at your option)
18 ;; any later version.
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.
30 ;;;_ + Commentary:
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.
44 ;;;_ + Contributors
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.
51 ;;; Code:
53 (require 'planner)
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))
70 map)
71 "Keymap for planner task overview buffers.")
73 (define-derived-mode planner-tasks-overview-mode planner-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*"
80 "Buffer name.")
82 ;;;###autoload
83 (defun planner-tasks-overview (start end)
84 "Display a task overview from START to END."
85 (interactive (list (planner-read-date)
86 (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-extract-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))))
99 ;;;###autoload
100 (defun planner-tasks-overview-jump-other-window ()
101 "Display the task under point in a different window."
102 (interactive)
103 (planner-tasks-overview-jump t))
105 ;;;###autoload
106 (defun planner-tasks-overview-jump (&optional other-window)
107 "Display the task under point."
108 (interactive "P")
109 (when other-window
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))
115 (widen)
116 (when (re-search-forward
117 (concat
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)
123 "Sort by FIELD."
124 (interactive)
125 (setq planner-tasks-overview-data
126 (sort planner-tasks-overview-data
127 (lambda (a b)
128 (cond
129 ((null (elt a field)) nil)
130 ((null (elt b field)) t)
131 ((string< (elt a field) (elt b field)))))))
132 (planner-tasks-overview-insert))
134 (defun planner-tasks-overview-sort-by-date ()
135 "Sort by date."
136 (interactive)
137 (planner-tasks-overview-sort-by-field 8))
139 (defun planner-tasks-overview-sort-by-plan ()
140 "Sort by plan."
141 (interactive)
142 (planner-tasks-overview-sort-by-field 7))
144 (defun planner-tasks-overview-sort-by-priority ()
145 "Sort by plan."
146 (interactive)
147 (planner-tasks-overview-sort-by-field 1))
149 (defun planner-tasks-overview-sort-by-status ()
150 "Sort by status."
151 (interactive)
152 (setq planner-tasks-overview-data
153 (sort planner-tasks-overview-data
154 (lambda (a b)
155 (if (string= (elt b 3)
156 (elt a 3))
157 (string< (elt a 1)
158 (elt b 1))
159 (member (elt b 3)
160 (member (elt a 3)
161 '("_" "o" "D" "P" "X" "C")))))))
162 (planner-tasks-overview-insert))
164 (defun planner-tasks-overview-insert ()
165 "Insert the textual representation for `planner-tasks-overview-data'."
166 (with-current-buffer (get-buffer-create "*planner tasks overview*")
167 (setq muse-current-project (muse-project planner-project))
168 (setq buffer-read-only nil)
169 (erase-buffer)
170 (let (last-date last-plan)
171 (mapcar
172 (lambda (item)
173 (let* ((date (planner-task-date item))
174 (plan (planner-task-plan item))
175 (text
176 (format "%10s | %s | %s %s | %s\n"
177 (if date
178 (planner-make-link
179 date
180 (format "%-10.10s"
181 (if (string= last-date date)
182 "\"\""
183 date)))
184 (format "%-10.10s" ""))
185 (if plan
186 (planner-make-link
187 plan
188 (format "%-20.20s"
189 (if (string= last-plan plan)
190 "\"\""
191 plan)))
192 (format "%-20.20s" ""))
193 (planner-task-priority item)
194 (planner-task-status item)
195 (planner-task-description item))))
196 (add-text-properties 0 (length text) (list 'info item)
197 text)
198 (insert text)
199 (setq last-date date)
200 (setq last-plan plan)))
201 planner-tasks-overview-data)
202 (goto-char (point-min))
203 (setq buffer-read-only t))))
205 ;; Improvements: sort?
206 ;;;###autoload
207 (defun planner-tasks-overview-show-summary (&optional file-list)
208 "Count unscheduled, scheduled, and completed tasks for FILE-LIST.
209 If called with an interactive prefix, prompt for the page(s) to
210 display. planner-multi is required for multiple pages."
211 (interactive
212 (list
213 (if current-prefix-arg
214 (planner-file-alist
216 (if (featurep 'planner-multi)
217 (mapcar 'planner-link-base
218 (planner-multi-split
219 (planner-read-non-date-page
220 (planner-file-alist))))
221 (list (planner-read-non-date-page
222 (planner-file-alist))))))))
223 (let (data total)
224 (with-planner
225 (setq data (planner-tasks-overview-get-summary file-list))
226 (with-current-buffer (get-buffer-create "*planner tasks overview*")
227 (setq buffer-read-only nil)
228 (erase-buffer)
229 (setq total (+ (elt data 0) (elt data 1) (elt data 2)))
230 (insert (format "Total unfinished, unscheduled tasks : %3d (%6.2f%%)\n"
231 (elt data 0) (/ (elt data 0) (* 0.01 total)))
232 (format "Total unfinished, scheduled tasks : %3d (%6.2f%%)\n"
233 (elt data 1) (/ (elt data 1) (* 0.01 total)))
234 (format "Total finished tasks : %3d (%6.2f%%)\n\n"
235 (elt data 2) (/ (elt data 2) (* 0.01 total))))
236 (insert (format "%-40s | Unsched | Sched | Complete | Total\n"
237 "Plan page"))
238 (mapcar
239 (lambda (row)
240 (let ((row-total (* 0.01 (+ (elt row 1) (elt row 2) (elt row 3)))))
241 (insert
242 (format "%s | %3d %3.0f%% | %3d %3.0f%% | %3d %3.0f%% | %3d %3.0f%%\n"
243 (planner-make-link
244 (elt row 0)
245 (format "%-40.40s" (elt row 0)))
246 (elt row 1)
247 (/ (elt row 1) row-total)
248 (elt row 2)
249 (/ (elt row 2) row-total)
250 (elt row 3)
251 (/ (elt row 3) row-total)
252 (+ (elt row 1) (elt row 2) (elt row 3))
253 (/ (+ (elt row 1) (elt row 2) (elt row 3))
254 (* 0.01 total))))))
255 (elt data 3))
256 (setq muse-current-project (muse-project planner-project))
257 (planner-mode)
258 (switch-to-buffer (current-buffer))))))
260 ;; Unfinished Finished % Complete
261 ;; Unscheduled Scheduled
262 (defun planner-tasks-overview-get-summary (&optional file-list)
263 "Return a summary of tasks on pages in FILE-LIST.
264 List is of the form (total-unfinished-unscheduled
265 total-unfinished-scheduled total-finished data), where data is a
266 list of the form (plan unfinished-unscheduled
267 unfinished-scheduled finished)."
268 (let ((total-unfinished-unscheduled 0)
269 (total-unfinished-scheduled 0)
270 (total-finished 0)
271 list)
272 (unless file-list (setq file-list (planner-file-alist)))
273 (with-temp-buffer
274 (with-planner
275 (while file-list
276 (unless (string-match planner-date-regexp (car (car file-list)))
277 (let ((unfinished-unscheduled 0)
278 (unfinished-scheduled 0)
279 (finished 0))
280 (erase-buffer)
281 (insert-file-contents (cdr (car file-list)))
282 (goto-char (point-min))
283 (while (re-search-forward planner-task-regexp nil t)
284 (let ((info (planner-task-info-from-string
285 (car (car file-list))
286 (buffer-substring
287 (planner-line-beginning-position)
288 (planner-line-end-position)))))
289 (cond
290 ((or (string= (planner-task-status info) "X")
291 (string= (planner-task-status info) "C"))
292 (setq finished (1+ finished)))
293 ((planner-task-date info)
294 (setq unfinished-scheduled (1+ unfinished-scheduled)))
295 (t (setq unfinished-unscheduled
296 (1+ unfinished-unscheduled))))))
297 (setq list (cons (list (car (car file-list))
298 unfinished-unscheduled
299 unfinished-scheduled
300 finished)
301 list))
302 (setq total-unfinished-unscheduled
303 (+ total-unfinished-unscheduled unfinished-unscheduled))
304 (setq total-unfinished-scheduled
305 (+ total-unfinished-scheduled unfinished-scheduled))
306 (setq total-finished
307 (+ total-finished finished))))
308 (setq file-list (cdr file-list)))))
309 (list total-unfinished-unscheduled
310 total-unfinished-scheduled
311 total-finished
312 list)))
314 (provide 'planner-tasks-overview)
316 ;;; planner-tasks-overview.el ends here